00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <algorithm>
00011 #include <cstdio>
00012 #include <cstring>
00013 #include <cassert>
00014
00015 #ifndef _WIN32
00016 #ifndef MACOSX_PB
00017 #include <config.h>
00018 #endif
00019 #endif
00020
00021 #include <celutil/debug.h>
00022 #include <celmath/frustum.h>
00023 #include <celmath/distance.h>
00024 #include <celmath/intersect.h>
00025 #include <celutil/utf8.h>
00026 #include <celutil/util.h>
00027 #include "gl.h"
00028 #include "astro.h"
00029 #include "glext.h"
00030 #include "vecgl.h"
00031 #include "glshader.h"
00032 #include "shadermanager.h"
00033 #include "spheremesh.h"
00034 #include "lodspheremesh.h"
00035 #include "model.h"
00036 #include "regcombine.h"
00037 #include "vertexprog.h"
00038 #include "texmanager.h"
00039 #include "meshmanager.h"
00040 #include "render.h"
00041
00042 using namespace std;
00043
00044 #define FOV 45.0f
00045 #define NEAR_DIST 0.5f
00046 #define FAR_DIST 1.0e9f
00047
00048
00049 #ifndef GL_COLOR_SUM_EXT
00050 #define GL_COLOR_SUM_EXT 0x8458
00051 #endif
00052
00053 static const float STAR_DISTANCE_LIMIT = 1.0e6f;
00054 static const double DSO_DISTANCE_LIMIT = 1.8e9;
00055 static const int REF_DISTANCE_TO_SCREEN = 400;
00056
00057 static const float X0_SOL = astro::AUtoKilometers(5.0f);
00058
00059 static const int StarVertexListSize = 1024;
00060
00061
00062
00063 static const float PixelOffset = 0.125f;
00064
00065
00066
00067
00068
00069 static const float MinNearPlaneDistance = 0.0001f;
00070 static const float MaxFarNearRatio = 2000.0f;
00071
00072 static const float RenderDistance = 50.0f;
00073
00074 static const float MaxScaledDiscStarSize = 8.0f;
00075
00076
00077
00078
00079 static const float MinOrbitSizeForLabel = 20.0f;
00080
00081
00082
00083 static const float MinFeatureSizeForLabel = 20.0f;
00084
00085
00086
00087 static bool commonDataInitialized = false;
00088
00089 static LODSphereMesh* lodSphere = NULL;
00090
00091 static Texture* normalizationTex = NULL;
00092
00093 static Texture* starTex = NULL;
00094 static Texture* glareTex = NULL;
00095 static Texture* shadowTex = NULL;
00096
00097
00098
00099
00100 static const float ShadowTextureScale = 15.0f / 16.0f;
00101
00102 static Texture* eclipseShadowTextures[4];
00103 static Texture* shadowMaskTexture = NULL;
00104 static Texture* penumbraFunctionTexture = NULL;
00105
00106 static const Color compassColor(0.4f, 0.4f, 1.0f);
00107
00108 static const float CoronaHeight = 0.2f;
00109
00110 static bool buggyVertexProgramEmulation = true;
00111
00112 struct SphericalCoordLabel
00113 {
00114 string label;
00115 float ra;
00116 float dec;
00117
00118 SphericalCoordLabel() : ra(0), dec(0) {};
00119 SphericalCoordLabel(float _ra, float _dec) : ra(_ra), dec(_dec)
00120 {
00121 }
00122 };
00123
00124 static int nCoordLabels = 32;
00125 static SphericalCoordLabel* coordLabels = NULL;
00126
00127 static const int MaxSkyRings = 32;
00128 static const int MaxSkySlices = 180;
00129 static const int MinSkySlices = 30;
00130
00131
00132 Renderer::Renderer() :
00133 context(0),
00134 windowWidth(0),
00135 windowHeight(0),
00136 fov(FOV),
00137 screenDpi(96),
00138 corrFac(1.12f),
00139 faintestAutoMag45deg(7.0f),
00140 renderMode(GL_FILL),
00141 labelMode(NoLabels),
00142 renderFlags(ShowStars | ShowPlanets),
00143 orbitMask(Body::Planet | Body::Moon),
00144 ambientLightLevel(0.1f),
00145 fragmentShaderEnabled(false),
00146 vertexShaderEnabled(false),
00147 brightnessBias(0.0f),
00148 saturationMagNight(1.0f),
00149 saturationMag(1.0f),
00150 starStyle(FuzzyPointStars),
00151 starVertexBuffer(NULL),
00152 useVertexPrograms(false),
00153 useRescaleNormal(false),
00154 usePointSprite(false),
00155 textureResolution(medres),
00156 minOrbitSize(MinOrbitSizeForLabel),
00157 distanceLimit(1.0e6f),
00158 minFeatureSize(MinFeatureSizeForLabel),
00159 locationFilter(~0),
00160 colorTemp(NULL)
00161 {
00162 starVertexBuffer = new StarVertexBuffer(2048);
00163 skyVertices = new SkyVertex[MaxSkySlices * (MaxSkyRings + 1)];
00164 skyIndices = new uint32[(MaxSkySlices + 1) * 2 * MaxSkyRings];
00165 skyContour = new SkyContourPoint[MaxSkySlices + 1];
00166 colorTemp = GetStarColorTable(ColorTable_Enhanced);
00167 }
00168
00169
00170 Renderer::~Renderer()
00171 {
00172 if (starVertexBuffer != NULL)
00173 delete starVertexBuffer;
00174 delete[] skyVertices;
00175 delete[] skyIndices;
00176 delete[] skyContour;
00177 }
00178
00179
00180 Renderer::DetailOptions::DetailOptions() :
00181 ringSystemSections(100),
00182 orbitPathSamplePoints(100),
00183 shadowTextureSize(256),
00184 eclipseTextureSize(128)
00185 {
00186 }
00187
00188
00189 static void StarTextureEval(float u, float v, float w,
00190 unsigned char *pixel)
00191 {
00192 float r = 1 - (float) sqrt(u * u + v * v);
00193 if (r < 0)
00194 r = 0;
00195 else if (r < 0.5f)
00196 r = 2.0f * r;
00197 else
00198 r = 1;
00199
00200 int pixVal = (int) (r * 255.99f);
00201 pixel[0] = pixVal;
00202 pixel[1] = pixVal;
00203 pixel[2] = pixVal;
00204 }
00205
00206 static void GlareTextureEval(float u, float v, float w,
00207 unsigned char *pixel)
00208 {
00209 float r = 0.9f - (float) sqrt(u * u + v * v);
00210 if (r < 0)
00211 r = 0;
00212
00213 int pixVal = (int) (r * 255.99f);
00214 pixel[0] = 65;
00215 pixel[1] = 64;
00216 pixel[2] = 65;
00217 pixel[3] = pixVal;
00218 }
00219
00220 static void ShadowTextureEval(float u, float v, float w,
00221 unsigned char *pixel)
00222 {
00223 float r = (float) sqrt(u * u + v * v);
00224
00225
00226
00227
00228 int pixVal = r < 15.0f / 16.0f ? 0 : 255;
00229 pixel[0] = pixVal;
00230 pixel[1] = pixVal;
00231 pixel[2] = pixVal;
00232 }
00233
00234
00236
00237
00238 static void PenumbraFunctionEval(float u, float v, float w,
00239 unsigned char *pixel)
00240 {
00241 u = (u + 1.0f) * 0.5f;
00242
00243
00244 unsigned char pixVal = (unsigned char) (::pow((double) u, 0.33) * 255.99);
00245
00246 pixel[0] = pixVal;
00247 }
00248
00249
00250
00251
00252 class ShadowTextureFunction : public TexelFunctionObject
00253 {
00254 public:
00255 ShadowTextureFunction(float _umbra) : umbra(_umbra) {};
00256 virtual void operator()(float u, float v, float w, unsigned char* pixel);
00257 float umbra;
00258 };
00259
00260 void ShadowTextureFunction::operator()(float u, float v, float w,
00261 unsigned char* pixel)
00262 {
00263 float r = (float) sqrt(u * u + v * v);
00264 int pixVal = 255;
00265
00266
00267
00268
00269 r = r / (15.0f / 16.0f);
00270 if (r < 1)
00271 {
00272
00273
00274
00275 if (r <= umbra)
00276 pixVal = 0;
00277 else
00278 pixVal = (int) (sqrt((r - umbra) / (1 - umbra)) * 255.99f);
00279 }
00280
00281 pixel[0] = pixVal;
00282 pixel[1] = pixVal;
00283 pixel[2] = pixVal;
00284 };
00285
00286
00287 class ShadowMaskTextureFunction : public TexelFunctionObject
00288 {
00289 public:
00290 ShadowMaskTextureFunction() {};
00291 virtual void operator()(float u, float v, float w, unsigned char* pixel);
00292 float dummy;
00293 };
00294
00295 void ShadowMaskTextureFunction::operator()(float u, float v, float w,
00296 unsigned char* pixel)
00297 {
00298 unsigned char a = u > 0.0f ? 255 : 0;
00299 pixel[0] = a;
00300 pixel[1] = a;
00301 pixel[2] = a;
00302 pixel[3] = a;
00303 }
00304
00305
00306 static void IllumMapEval(float x, float y, float z,
00307 unsigned char* pixel)
00308 {
00309 Vec3f v(x, y, z);
00310 Vec3f u(0, 0, 1);
00311
00312 #if 0
00313 Vec3f n(0, 0, 1);
00314
00315 float c = v * n;
00316 if (c < 0.0f)
00317 {
00318 u = v;
00319 }
00320 else
00321 {
00322 c = (1 - ((1 - c))) * 1.0f;
00323 u = v + (c * n);
00324 u.normalize();
00325 }
00326 #else
00327 u = v;
00328 #endif
00329
00330 pixel[0] = 128 + (int) (127 * u.x);
00331 pixel[1] = 128 + (int) (127 * u.y);
00332 pixel[2] = 128 + (int) (127 * u.z);
00333 }
00334
00335 bool operator<(const RenderListEntry& a, const RenderListEntry& b)
00336 {
00337
00338
00339
00340
00341
00342
00343
00344 if (a.radius < b.radius)
00345 {
00346 Vec3f dir = a.position - Point3f(0.0f, 0.0f, 0.0f);
00347 float distance;
00348 dir.normalize();
00349 if (testIntersection(Ray3f(Point3f(0.0f, 0.0f, 0.0f), dir),
00350 Spheref(b.position, b.radius),
00351 distance))
00352 {
00353 return a.distance - a.radius < distance;
00354 }
00355 }
00356 else
00357 {
00358 Vec3f dir = b.position - Point3f(0.0f, 0.0f, 0.0f);
00359 float distance;
00360 dir.normalize();
00361 if (testIntersection(Ray3f(Point3f(0.0f, 0.0f, 0.0f), dir),
00362 Spheref(a.position, a.radius),
00363 distance))
00364 {
00365 return distance < b.distance - b.radius;
00366 }
00367 }
00368
00369 return a.distance - a.radius < b.distance - b.radius;
00370 }
00371
00372
00373 bool operator<(const Renderer::Label& a, const Renderer::Label& b)
00374 {
00375 return a.position.z > b.position.z;
00376 }
00377
00378
00379 bool Renderer::init(GLContext* _context,
00380 int winWidth, int winHeight,
00381 DetailOptions& _detailOptions)
00382 {
00383 context = _context;
00384 detailOptions = _detailOptions;
00385
00386
00387 if (!commonDataInitialized)
00388 {
00389 lodSphere = new LODSphereMesh();
00390
00391 starTex = CreateProceduralTexture(64, 64, GL_RGB, StarTextureEval);
00392
00393 glareTex = LoadTextureFromFile("textures/flare.jpg");
00394 if (glareTex == NULL)
00395 glareTex = CreateProceduralTexture(64, 64, GL_RGB, GlareTextureEval);
00396
00397
00398
00399
00400
00401
00402
00403
00404 Texture::AddressMode shadowTexAddress = Texture::EdgeClamp;
00405 Texture::MipMapMode shadowTexMip = Texture::NoMipMaps;
00406 useClampToBorder = context->extensionSupported("GL_ARB_texture_border_clamp");
00407 if (useClampToBorder)
00408 {
00409 shadowTexAddress = Texture::BorderClamp;
00410 shadowTexMip = Texture::DefaultMipMaps;
00411 }
00412
00413 shadowTex = CreateProceduralTexture(detailOptions.shadowTextureSize,
00414 detailOptions.shadowTextureSize,
00415 GL_RGB,
00416 ShadowTextureEval,
00417 shadowTexAddress, shadowTexMip);
00418 shadowTex->setBorderColor(Color::White);
00419
00420
00421 {
00422 for (int i = 0; i < 4; i++)
00423 {
00424 ShadowTextureFunction func(i * 0.25f);
00425 eclipseShadowTextures[i] =
00426 CreateProceduralTexture(detailOptions.eclipseTextureSize,
00427 detailOptions.eclipseTextureSize,
00428 GL_RGB, func,
00429 shadowTexAddress, shadowTexMip);
00430 if (eclipseShadowTextures[i] != NULL)
00431 {
00432
00433 eclipseShadowTextures[i]->setBorderColor(Color::White);
00434 }
00435 }
00436 }
00437
00438
00439 {
00440 ShadowMaskTextureFunction func;
00441 shadowMaskTexture = CreateProceduralTexture(128, 2, GL_RGBA, func);
00442
00443 }
00444
00445
00446
00447 penumbraFunctionTexture = CreateProceduralTexture(512, 1, GL_LUMINANCE,
00448 PenumbraFunctionEval,
00449 Texture::EdgeClamp);
00450
00451 if (context->extensionSupported("GL_EXT_texture_cube_map"))
00452 {
00453
00454 normalizationTex = CreateProceduralCubeMap(64, GL_RGB, IllumMapEval);
00455 }
00456
00457
00458 {
00459 char buf[10];
00460 int i;
00461
00462 coordLabels = new SphericalCoordLabel[nCoordLabels];
00463 for (i = 0; i < 12; i++)
00464 {
00465 coordLabels[i].ra = float(i * 2);
00466 coordLabels[i].dec = 0;
00467 sprintf(buf, "%dh", i * 2);
00468 coordLabels[i].label = string(buf);
00469 }
00470
00471 coordLabels[12] = SphericalCoordLabel(0, -75);
00472 coordLabels[13] = SphericalCoordLabel(0, -60);
00473 coordLabels[14] = SphericalCoordLabel(0, -45);
00474 coordLabels[15] = SphericalCoordLabel(0, -30);
00475 coordLabels[16] = SphericalCoordLabel(0, -15);
00476 coordLabels[17] = SphericalCoordLabel(0, 15);
00477 coordLabels[18] = SphericalCoordLabel(0, 30);
00478 coordLabels[19] = SphericalCoordLabel(0, 45);
00479 coordLabels[20] = SphericalCoordLabel(0, 60);
00480 coordLabels[21] = SphericalCoordLabel(0, 75);
00481 for (i = 22; i < nCoordLabels; i++)
00482 {
00483 coordLabels[i].ra = 12;
00484 coordLabels[i].dec = coordLabels[i - 10].dec;
00485 }
00486
00487 for (i = 12; i < nCoordLabels; i++)
00488 {
00489 char buf[10];
00490 sprintf(buf, "%d", (int) coordLabels[i].dec);
00491 coordLabels[i].label = string(buf);
00492 }
00493 }
00494
00495 commonDataInitialized = true;
00496 }
00497
00498 if (context->extensionSupported("GL_EXT_rescale_normal"))
00499 {
00500
00501
00502 DPRINTF(1, "Renderer: EXT_rescale_normal supported.\n");
00503 useRescaleNormal = true;
00504 glEnable(GL_RESCALE_NORMAL_EXT);
00505 }
00506
00507 if (context->extensionSupported("GL_ARB_point_sprite"))
00508 {
00509 DPRINTF(1, "Renderer: point sprites supported.\n");
00510 usePointSprite = true;
00511 }
00512
00513
00514 char* glRenderer = (char*) glGetString(GL_RENDERER);
00515 if (glRenderer != NULL)
00516 {
00517
00518
00519
00520 if (strstr(glRenderer, "GeForce3") != NULL ||
00521 strstr(glRenderer, "GeForce4") != NULL)
00522 {
00523 buggyVertexProgramEmulation = false;
00524 }
00525
00526 if (strstr(glRenderer, "Savage4") != NULL ||
00527 strstr(glRenderer, "ProSavage") != NULL)
00528 {
00529
00530
00531
00532 useRescaleNormal = true;
00533 }
00534 }
00535
00536
00537
00538
00539 char* glVersion = (char*) glGetString(GL_VERSION);
00540 if (glVersion != NULL)
00541 {
00542 int major = 0, minor = 0, extra = 0;
00543 int nScanned = sscanf(glVersion, "%d.%d.%d", &major, &minor, &extra);
00544
00545 if (nScanned >= 2)
00546 {
00547 if (major > 1 || minor > 3 || (minor == 3 && extra >= 1))
00548 buggyVertexProgramEmulation = false;
00549 }
00550 }
00551
00552 glLoadIdentity();
00553
00554 glEnable(GL_CULL_FACE);
00555 glCullFace(GL_BACK);
00556
00557 glEnable(GL_COLOR_MATERIAL);
00558 glEnable(GL_LIGHTING);
00559 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
00560
00561
00562 glDepthFunc(GL_LEQUAL);
00563
00564 resize(winWidth, winHeight);
00565
00566 return true;
00567 }
00568
00569
00570 void Renderer::resize(int width, int height)
00571 {
00572 windowWidth = width;
00573 windowHeight = height;
00574
00575 }
00576
00577 float Renderer::calcPixelSize(float fovY, float windowHeight)
00578 {
00579 return 2 * (float) tan(degToRad(fovY / 2.0)) / (float) windowHeight;
00580 }
00581
00582 void Renderer::setFieldOfView(float _fov)
00583 {
00584 fov = _fov;
00585 corrFac = (0.12f * fov/FOV * fov/FOV + 1.0f);
00586 }
00587
00588 int Renderer::getScreenDpi() const
00589 {
00590 return screenDpi;
00591 }
00592
00593 void Renderer::setScreenDpi(int _dpi)
00594 {
00595 screenDpi = _dpi;
00596 }
00597
00598 void Renderer::setFaintestAM45deg(float _faintestAutoMag45deg)
00599 {
00600 faintestAutoMag45deg = _faintestAutoMag45deg;
00601 }
00602
00603 float Renderer::getFaintestAM45deg()
00604 {
00605 return faintestAutoMag45deg;
00606 }
00607
00608 unsigned int Renderer::getResolution()
00609 {
00610 return textureResolution;
00611 }
00612
00613
00614 void Renderer::setResolution(unsigned int resolution)
00615 {
00616 if (resolution < TEXTURE_RESOLUTION)
00617 textureResolution = resolution;
00618 }
00619
00620
00621 TextureFont* Renderer::getFont() const
00622 {
00623 return font;
00624 }
00625
00626 void Renderer::setFont(TextureFont* txf)
00627 {
00628 font = txf;
00629 }
00630
00631 void Renderer::setRenderMode(int _renderMode)
00632 {
00633 renderMode = _renderMode;
00634 }
00635
00636 int Renderer::getRenderFlags() const
00637 {
00638 return renderFlags;
00639 }
00640
00641 void Renderer::setRenderFlags(int _renderFlags)
00642 {
00643 renderFlags = _renderFlags;
00644 }
00645
00646 int Renderer::getLabelMode() const
00647 {
00648 return labelMode;
00649 }
00650
00651 void Renderer::setLabelMode(int _labelMode)
00652 {
00653 labelMode = _labelMode;
00654 }
00655
00656 int Renderer::getOrbitMask() const
00657 {
00658 return orbitMask;
00659 }
00660
00661 void Renderer::setOrbitMask(int mask)
00662 {
00663 orbitMask = mask;
00664 }
00665
00666
00667 const ColorTemperatureTable*
00668 Renderer::getStarColorTable() const
00669 {
00670 return colorTemp;
00671 }
00672
00673
00674 void
00675 Renderer::setStarColorTable(const ColorTemperatureTable* ct)
00676 {
00677 colorTemp = ct;
00678 }
00679
00680
00681 void Renderer::addLabelledStar(Star* star, const string& label)
00682 {
00683 labelledStars.push_back(StarLabel(star, label));
00684 }
00685
00686
00687 void Renderer::clearLabelledStars()
00688 {
00689 labelledStars.clear();
00690 }
00691
00692
00693 float Renderer::getAmbientLightLevel() const
00694 {
00695 return ambientLightLevel;
00696 }
00697
00698
00699 void Renderer::setAmbientLightLevel(float level)
00700 {
00701 ambientLightLevel = level;
00702 }
00703
00704
00705 float Renderer::getMinimumFeatureSize() const
00706 {
00707 return minFeatureSize;
00708 }
00709
00710
00711 void Renderer::setMinimumFeatureSize(float pixels)
00712 {
00713 minFeatureSize = pixels;
00714 }
00715
00716
00717 float Renderer::getMinimumOrbitSize() const
00718 {
00719 return minOrbitSize;
00720 }
00721
00722
00723
00724 void Renderer::setMinimumOrbitSize(float pixels)
00725 {
00726 minOrbitSize = pixels;
00727 }
00728
00729
00730 float Renderer::getDistanceLimit() const
00731 {
00732 return distanceLimit;
00733 }
00734
00735
00736 void Renderer::setDistanceLimit(float distanceLimit_)
00737 {
00738 distanceLimit = distanceLimit_;
00739 }
00740
00741
00742 bool Renderer::getFragmentShaderEnabled() const
00743 {
00744 return fragmentShaderEnabled;
00745 }
00746
00747 void Renderer::setFragmentShaderEnabled(bool enable)
00748 {
00749 fragmentShaderEnabled = enable && fragmentShaderSupported();
00750 }
00751
00752 bool Renderer::fragmentShaderSupported() const
00753 {
00754 return context->bumpMappingSupported();
00755 }
00756
00757 bool Renderer::getVertexShaderEnabled() const
00758 {
00759 return vertexShaderEnabled;
00760 }
00761
00762 void Renderer::setVertexShaderEnabled(bool enable)
00763 {
00764 vertexShaderEnabled = enable && vertexShaderSupported();
00765 }
00766
00767 bool Renderer::vertexShaderSupported() const
00768 {
00769 return useVertexPrograms;
00770 }
00771
00772
00773 void Renderer::addLabel(string text,
00774 Color color,
00775 const Point3f& pos,
00776 float depth)
00777 {
00778 double winX, winY, winZ;
00779 int view[4] = { 0, 0, 0, 0 };
00780 view[0] = -windowWidth / 2;
00781 view[1] = -windowHeight / 2;
00782 view[2] = windowWidth;
00783 view[3] = windowHeight;
00784 depth = (float) (pos.x * modelMatrix[2] +
00785 pos.y * modelMatrix[6] +
00786 pos.z * modelMatrix[10]);
00787 if (gluProject(pos.x, pos.y, pos.z,
00788 modelMatrix,
00789 projMatrix,
00790 (const GLint*) view,
00791 &winX, &winY, &winZ) != GL_FALSE)
00792 {
00793 Label l;
00794 l.text = ReplaceGreekLetterAbbr(text.c_str());
00795 l.color = color;
00796 l.position = Point3f((float) winX, (float) winY, -depth);
00797 labels.insert(labels.end(), l);
00798 }
00799 }
00800
00801
00802 void Renderer::addSortedLabel(string text, Color color, const Point3f& pos)
00803 {
00804 double winX, winY, winZ;
00805 int view[4] = { 0, 0, 0, 0 };
00806 view[0] = -windowWidth / 2;
00807 view[1] = -windowHeight / 2;
00808 view[2] = windowWidth;
00809 view[3] = windowHeight;
00810 float depth = (float) (pos.x * modelMatrix[2] +
00811 pos.y * modelMatrix[6] +
00812 pos.z * modelMatrix[10]);
00813 if (gluProject(pos.x, pos.y, pos.z,
00814 modelMatrix,
00815 projMatrix,
00816 (const GLint*) view,
00817 &winX, &winY, &winZ) != GL_FALSE)
00818 {
00819 Label l;
00820 l.text = ReplaceGreekLetterAbbr(_(text.c_str()));
00821 l.color = color;
00822 l.position = Point3f((float) winX, (float) winY, -depth);
00823 depthSortedLabels.insert(depthSortedLabels.end(), l);
00824 }
00825 }
00826
00827
00828 void Renderer::clearLabels()
00829 {
00830 labels.clear();
00831 depthSortedLabels.clear();
00832 }
00833
00834
00835 static void enableSmoothLines()
00836 {
00837
00838 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00839 glEnable(GL_LINE_SMOOTH);
00840 glLineWidth(1.5f);
00841 }
00842
00843 static void disableSmoothLines()
00844 {
00845
00846 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
00847 glDisable(GL_LINE_SMOOTH);
00848 glLineWidth(1.0f);
00849 }
00850
00851
00852 class OrbitRenderer : public OrbitSampleProc
00853 {
00854 public:
00855 OrbitRenderer() {};
00856
00857 void sample(double, const Point3d& p)
00858 {
00859 glVertex3f(astro::kilometersToAU((float) p.x * 100),
00860 astro::kilometersToAU((float) p.y * 100),
00861 astro::kilometersToAU((float) p.z * 100));
00862
00863 };
00864
00865 private:
00866 int dummy;
00867 };
00868
00869
00870 class OrbitSampler : public OrbitSampleProc
00871 {
00872 public:
00873 vector<Renderer::OrbitSample>* samples;
00874
00875 OrbitSampler(vector<Renderer::OrbitSample>* _samples) : samples(_samples) {};
00876 void sample(double t, const Point3d& p)
00877 {
00878 Renderer::OrbitSample samp;
00879 samp.pos = Point3f((float) p.x, (float) p.y, (float) p.z);
00880 samp.t = t;
00881 samples->insert(samples->end(), samp);
00882 };
00883 };
00884
00885
00886 void renderOrbitColor(const Body* body, bool selected)
00887 {
00888 if (selected)
00889 {
00890
00891 glColor4f(1, 0, 0, 1);
00892 }
00893 else
00894 {
00895 switch (body->getClassification())
00896 {
00897 case Body::Moon:
00898 glColor4f(0.0f, 0.2f, 0.5f, 1.0f);
00899 break;
00900 case Body::Asteroid:
00901 glColor4f(0.35f, 0.2f, 0.0f, 1.0f);
00902 break;
00903 case Body::Comet:
00904 glColor4f(0.0f, 0.5f, 0.5f, 1.0f);
00905 break;
00906 case Body::Spacecraft:
00907 glColor4f(0.4f, 0.4f, 0.4f, 1.0f);
00908 break;
00909 case Body::Planet:
00910 default:
00911 glColor4f(0.0f, 0.4f, 1.0f, 1.0f);
00912 break;
00913 }
00914 }
00915 }
00916
00917
00918 void Renderer::renderOrbit(Body* body, double t)
00919 {
00920 vector<OrbitSample>* trajectory = NULL;
00921 for (vector<CachedOrbit*>::const_iterator iter = orbitCache.begin();
00922 iter != orbitCache.end(); iter++)
00923 {
00924 if ((*iter)->body == body)
00925 {
00926 (*iter)->keep = true;
00927 trajectory = &((*iter)->trajectory);
00928 break;
00929 }
00930 }
00931
00932
00933 if (trajectory == NULL)
00934 {
00935 CachedOrbit* orbit = NULL;
00936
00937
00938 for (vector<CachedOrbit*>::const_iterator iter = orbitCache.begin();
00939 iter != orbitCache.end(); iter++)
00940 {
00941 if ((*iter)->body == NULL)
00942 {
00943 orbit = *iter;
00944 orbit->trajectory.clear();
00945 break;
00946 }
00947 }
00948
00949
00950 bool reuse = true;
00951 if (orbit == NULL)
00952 {
00953 orbit = new CachedOrbit();
00954 reuse = false;
00955 }
00956
00957 double startTime = t;
00958 int nSamples = detailOptions.orbitPathSamplePoints;
00959
00960
00961
00962
00963
00964 if (!body->getOrbit()->isPeriodic())
00965 {
00966 double begin = 0.0, end = 0.0;
00967 body->getOrbit()->getValidRange(begin, end);
00968
00969 if (begin != end)
00970 {
00971 startTime = begin;
00972 nSamples = (int) (body->getOrbit()->getPeriod() * 100.0);
00973 nSamples = max(min(nSamples, 1000), 100);
00974 }
00975 }
00976
00977 orbit->body = body;
00978 orbit->keep = true;
00979 OrbitSampler sampler(&orbit->trajectory);
00980 body->getOrbit()->sample(startTime,
00981 body->getOrbit()->getPeriod(),
00982 nSamples,
00983 sampler);
00984 trajectory = &orbit->trajectory;
00985
00986
00987 if (!reuse)
00988 orbitCache.insert(orbitCache.end(), orbit);
00989 }
00990
00991
00992 if (body->getOrbit()->isPeriodic())
00993 glBegin(GL_LINE_LOOP);
00994 else
00995 glBegin(GL_LINE_STRIP);
00996
00997 if ((renderFlags & ShowPartialTrajectories) == 0 ||
00998 body->getOrbit()->isPeriodic())
00999 {
01000
01001 for (vector<OrbitSample>::const_iterator p = trajectory->begin();
01002 p != trajectory->end(); p++)
01003 {
01004 glVertex3f(astro::kilometersToAU(p->pos.x),
01005 astro::kilometersToAU(p->pos.y),
01006 astro::kilometersToAU(p->pos.z));
01007 }
01008 }
01009 else
01010 {
01011 vector<OrbitSample>::const_iterator p;
01012
01013
01014 for (p = trajectory->begin(); p != trajectory->end() && p->t < t; p++)
01015 {
01016 glVertex3f(astro::kilometersToAU(p->pos.x),
01017 astro::kilometersToAU(p->pos.y),
01018 astro::kilometersToAU(p->pos.z));
01019 }
01020
01021
01022
01023 if (p != trajectory->end())
01024 {
01025 Point3d pos = body->getOrbit()->positionAtTime(t);
01026 glVertex3f((float) astro::kilometersToAU(pos.x),
01027 (float) astro::kilometersToAU(pos.y),
01028 (float) astro::kilometersToAU(pos.z));
01029 }
01030 }
01031
01032
01033 glEnd();
01034 }
01035
01036
01037 void Renderer::renderOrbits(PlanetarySystem* planets,
01038 const Selection& sel,
01039 double t,
01040 const Point3d& observerPos,
01041 const Point3d& center)
01042 {
01043 if (planets == NULL)
01044 return;
01045
01046 double distance = (center - observerPos).length();
01047
01048 int nBodies = planets->getSystemSize();
01049 for (int i = 0; i < nBodies; i++)
01050 {
01051 Body* body = planets->getBody(i);
01052
01053
01054 if ((body->getClassification() & orbitMask) != 0 || body == sel.body())
01055 {
01056 renderOrbitColor(body, body == sel.body());
01057
01058 float orbitRadiusInPixels =
01059 (float) (body->getOrbit()->getBoundingRadius() /
01060 (distance * pixelSize));
01061 if (orbitRadiusInPixels > minOrbitSize)
01062 {
01063 float farDistance =
01064 (float) (body->getOrbit()->getBoundingRadius() + distance);
01065 farDistance = astro::kilometersToAU(farDistance);
01066
01067
01068
01069 glMatrixMode(GL_PROJECTION);
01070 glLoadIdentity();
01071 gluPerspective(fov,
01072 (float) windowWidth / (float) windowHeight,
01073 max( farDistance * 1e-6f, (float)(1e-5/2./tan(fov*3.14159/360.0)) ),
01074 farDistance * 1.1f );
01075 glMatrixMode(GL_MODELVIEW);
01076 renderOrbit(body, t);
01077
01078 if (body->getSatellites() != NULL)
01079 {
01080 Point3d localPos = body->getOrbit()->positionAtTime(t);
01081 Quatd rotation =
01082 Quatd::yrotation(body->getRotationElements().ascendingNode) *
01083 Quatd::xrotation(body->getRotationElements().obliquity);
01084 double scale = astro::kilometersToAU(1.0);
01085 glPushMatrix();
01086 glTranslated(localPos.x * scale,
01087 localPos.y * scale,
01088 localPos.z * scale);
01089 glRotate(rotation);
01090 renderOrbits(body->getSatellites(), sel, t,
01091 observerPos,
01092 body->getHeliocentricPosition(t));
01093 glPopMatrix();
01094 }
01095 }
01096 }
01097 }
01098 }
01099
01100
01101 void transformOrbits(const PlanetarySystem *system)
01102 {
01103 if (system->getPrimaryBody())
01104 {
01105 const Body *body = system->getPrimaryBody();
01106 transformOrbits(body->getSystem());
01107 Quatd rotation =
01108 Quatd::yrotation(body->getRotationElements().ascendingNode) *
01109 Quatd::xrotation(body->getRotationElements().obliquity);
01110 glRotate(rotation);
01111 }
01112 }
01113
01114
01115 void Renderer::renderForegroundOrbits(const PlanetarySystem* system,
01116 const Point3f ¢er,
01117 float distance,
01118 float discSizeInPixels,
01119 const Selection& sel,
01120 double t)
01121 {
01122
01123
01124 if ((renderFlags & ShowOrbits) == 0 || orbitMask == 0)
01125 return;
01126 if (system == NULL)
01127 return;
01128 if (discSizeInPixels < minOrbitSize)
01129 return;
01130
01131 distance = astro::kilometersToAU(distance);
01132 double scale = astro::kilometersToAU(1.0);
01133 glPushMatrix();
01134 glTranslated(center.x * scale,
01135 center.y * scale,
01136 center.z * scale);
01137
01138 glDisable(GL_LIGHTING);
01139 glDisable(GL_TEXTURE_2D);
01140 if ((renderFlags & ShowSmoothLines) != 0)
01141 enableSmoothLines();
01142 transformOrbits(system);
01143
01144 glMatrixMode(GL_PROJECTION);
01145 glLoadIdentity();
01146 gluPerspective(fov,
01147 (float) windowWidth / (float) windowHeight,
01148 max( distance * 1e-6f,
01149 (float)(1e-5/2./tan(fov*3.14159/360.0)) ),
01150 distance);
01151
01152 glMatrixMode(GL_MODELVIEW);
01153
01154 int nBodies = system->getSystemSize();
01155 for (int i = 0; i < nBodies; i++)
01156 {
01157 Body* body = system->getBody(i);
01158
01159
01160 if ((body->getClassification() & orbitMask) == 0 &&
01161 body != sel.body())
01162 continue;
01163 renderOrbitColor(body, body == sel.body());
01164 renderOrbit(body, t);
01165 }
01166
01167 if ((renderFlags & ShowSmoothLines) != 0)
01168 disableSmoothLines();
01169 glPopMatrix();
01170 }
01171
01172
01173
01174
01175 static Point3d astrocentricPosition(const UniversalCoord& pos,
01176 const Star& star,
01177 double t)
01178 {
01179 UniversalCoord starPos = star.getPosition(t);
01180
01181 Vec3d v = pos - starPos;
01182 return Point3d(astro::microLightYearsToKilometers(v.x),
01183 astro::microLightYearsToKilometers(v.y),
01184 astro::microLightYearsToKilometers(v.z));
01185 }
01186
01187
01188 void Renderer::autoMag(float& faintestMag)
01189 {
01190 float fieldCorr = 2.0f * FOV/(fov + FOV);
01191 faintestMag = (float) (faintestAutoMag45deg * sqrt(fieldCorr));
01192 saturationMag = saturationMagNight * (1.0f + fieldCorr * fieldCorr);
01193 }
01194
01195
01196
01197
01198 static void
01199 setupLightSources(const vector<const Star*>& nearStars,
01200 const Star& sun,
01201 double t,
01202 vector<Renderer::LightSource>& lightSources)
01203 {
01204 UniversalCoord center = sun.getPosition(t);
01205
01206 lightSources.clear();
01207
01208 for (vector<const Star*>::const_iterator iter = nearStars.begin();
01209 iter != nearStars.end(); iter++)
01210 {
01211 if ((*iter)->getVisibility())
01212 {
01213 Vec3d v = ((*iter)->getPosition(t) - center) *
01214 astro::microLightYearsToKilometers(1.0);
01215
01216 Renderer::LightSource ls;
01217 ls.position = Point3d(v.x, v.y, v.z);
01218 ls.luminosity = (*iter)->getLuminosity();
01219 ls.radius = (*iter)->getRadius();
01220
01221
01222
01223
01224
01225
01226
01227
01228 float temp = (*iter)->getTemperature();
01229 if (temp > 30000.0f)
01230 ls.color = Color(0.8f, 0.8f, 1.0f);
01231 else if (temp > 10000.0f)
01232 ls.color = Color(0.9f, 0.9f, 1.0f);
01233 else if (temp > 5400.0f)
01234 ls.color = Color(1.0f, 1.0f, 1.0f);
01235 else if (temp > 3900.0f)
01236 ls.color = Color(1.0f, 0.9f, 0.8f);
01237 else if (temp > 2000.0f)
01238 ls.color = Color(1.0f, 0.7f, 0.7f);
01239 else
01240 ls.color = Color(1.0f, 0.4f, 0.4f);
01241
01242 lightSources.push_back(ls);
01243 }
01244 }
01245 }
01246
01247
01248 void Renderer::render(const Observer& observer,
01249 const Universe& universe,
01250 float faintestMagNight,
01251 const Selection& sel)
01252 {
01253
01254 double now = observer.getTime();
01255
01256
01257 setFieldOfView(radToDeg(observer.getFOV()));
01258 pixelSize = calcPixelSize(fov, (float) windowHeight);
01259
01260 glMatrixMode(GL_PROJECTION);
01261 glLoadIdentity();
01262 gluPerspective(fov,
01263 (float) windowWidth / (float) windowHeight,
01264 NEAR_DIST, FAR_DIST);
01265
01266
01267 glMatrixMode(GL_MODELVIEW);
01268
01269
01270 displayedSurface = observer.getDisplayedSurface();
01271
01272 locationFilter = observer.getLocationFilter();
01273
01274
01275 Point3f observerPos = (Point3f) observer.getPosition();
01276 observerPos.x *= 1e-6f;
01277 observerPos.y *= 1e-6f;
01278 observerPos.z *= 1e-6f;
01279 glPushMatrix();
01280 glRotate(observer.getOrientation());
01281
01282
01283
01284 glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
01285 glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
01286
01287 clearLabels();
01288
01289
01290
01291
01292 renderList.clear();
01293
01294
01295 if ((renderFlags & ShowAutoMag) != 0)
01296 {
01297 autoMag(faintestMag);
01298 }
01299 else
01300 {
01301 faintestMag = faintestMagNight;
01302 saturationMag = saturationMagNight;
01303 }
01304
01305
01306
01307
01308
01309 faintestPlanetMag = faintestMag;
01310
01311 if (renderFlags & ShowPlanets)
01312 {
01313 nearStars.clear();
01314 universe.getNearStars(observer.getPosition(), 1.0f, nearStars);
01315
01316 unsigned int solarSysIndex = 0;
01317 for (vector<const Star*>::const_iterator iter = nearStars.begin();
01318 iter != nearStars.end(); iter++)
01319 {
01320 const Star* sun = *iter;
01321 SolarSystem* solarSystem = universe.getSolarSystem(sun);
01322 if (solarSystem != NULL)
01323 {
01324 setupLightSources(nearStars, *sun, now,
01325 lightSourceLists[solarSysIndex]);
01326 renderPlanetarySystem(*sun,
01327 *solarSystem->getPlanets(),
01328 observer,
01329 now,
01330 solarSysIndex,
01331 (labelMode & (BodyLabelMask)) != 0);
01332 solarSysIndex++;
01333 }
01334 }
01335 starTex->bind();
01336 }
01337
01338 Color skyColor(0.0f, 0.0f, 0.0f);
01339
01340
01341
01342
01343
01344 if ((renderFlags & ShowAtmospheres) != 0)
01345 {
01346 for (vector<RenderListEntry>::iterator iter = renderList.begin();
01347 iter != renderList.end(); iter++)
01348 {
01349 if (iter->body != NULL && iter->body->getAtmosphere() != NULL)
01350 {
01351
01352
01353
01354
01355 const Atmosphere* atmosphere = iter->body->getAtmosphere();
01356 float radius = iter->body->getRadius();
01357 float oblateness = iter->body->getOblateness();
01358 Vec3f recipSemiAxes(1.0f, 1.0f / (1.0f - oblateness), 1.0f);
01359 Mat3f A = Mat3f::scaling(recipSemiAxes);
01360 Vec3f eyeVec = iter->position - Point3f(0.0f, 0.0f, 0.0f);
01361 eyeVec *= (1.0f / radius);
01362
01363
01364 Quatd qd = iter->body->getEclipticalToEquatorial(now);
01365 Quatf q((float) qd.w, (float) qd.x, (float) qd.y, (float) qd.z);
01366 eyeVec = eyeVec * conjugate(q).toMatrix3();
01367
01368
01369
01370
01371
01372 float ellipDist = (float) sqrt((eyeVec * A) * (eyeVec * A)) - 1.0f;
01373 if (ellipDist < atmosphere->height / radius &&
01374 atmosphere->height > 0.0f)
01375 {
01376 float density = 1.0f - ellipDist /
01377 (atmosphere->height / radius);
01378 if (density > 1.0f)
01379 density = 1.0f;
01380
01381 Vec3f sunDir = iter->sun;
01382 Vec3f normal = Point3f(0.0f, 0.0f, 0.0f) - iter->position;
01383 sunDir.normalize();
01384 normal.normalize();
01385 float illumination = Math<float>::clamp((sunDir * normal) + 0.2f);
01386
01387 float lightness = illumination * density;
01388 faintestMag = faintestMag - 15.0f * lightness;
01389 saturationMag = saturationMag - 15.0f * lightness;
01390 }
01391 }
01392 }
01393 }
01394
01395
01396
01397
01398
01399
01400
01401
01402 if (faintestMag - saturationMag >= 4.0f)
01403 brightnessScale = 1.0f / (faintestMag - saturationMag);
01404 else
01405 brightnessScale = 0.25f;
01406
01407 ambientColor = Color(ambientLightLevel, ambientLightLevel, ambientLightLevel);
01408
01409
01410
01411 glAmbientLightColor(ambientColor);
01412
01413 glClearColor(skyColor.red(), skyColor.green(), skyColor.blue(), 1);
01414 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01415
01416 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
01417
01418 glDisable(GL_LIGHTING);
01419 glDepthMask(GL_FALSE);
01420 glEnable(GL_BLEND);
01421 glEnable(GL_TEXTURE_2D);
01422
01423 if ((renderFlags & ShowCelestialSphere) != 0)
01424 {
01425 glColor4f(0.3f, 0.7f, 0.7f, 0.55f);
01426 glDisable(GL_TEXTURE_2D);
01427 if ((renderFlags & ShowSmoothLines) != 0)
01428 enableSmoothLines();
01429 renderCelestialSphere(observer);
01430 if ((renderFlags & ShowSmoothLines) != 0)
01431 disableSmoothLines();
01432 glEnable(GL_BLEND);
01433 glEnable(GL_TEXTURE_2D);
01434 }
01435
01436 if (universe.getDSOCatalog() != NULL)
01437 renderDeepSkyObjects(universe, observer, faintestMag);
01438
01439
01440 glPushMatrix();
01441 glTranslatef(-observerPos.x, -observerPos.y, -observerPos.z);
01442
01443 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
01444 if ((renderFlags & ShowStars) != 0 && universe.getStarCatalog() != NULL)
01445 renderStars(*universe.getStarCatalog(), faintestMag, observer);
01446
01447
01448 if ((renderFlags & ShowDiagrams) != 0 && universe.getAsterisms() != NULL)
01449 {
01450 glColor4f(0.28f, 0.0f, 0.66f, 0.96f);
01451 glDisable(GL_TEXTURE_2D);
01452 if ((renderFlags & ShowSmoothLines) != 0)
01453 enableSmoothLines();
01454 AsterismList* asterisms = universe.getAsterisms();
01455 for (AsterismList::const_iterator iter = asterisms->begin();
01456 iter != asterisms->end(); iter++)
01457 {
01458 Asterism* ast = *iter;
01459
01460 for (int i = 0; i < ast->getChainCount(); i++)
01461 {
01462 const Asterism::Chain& chain = ast->getChain(i);
01463
01464 glBegin(GL_LINE_STRIP);
01465 for (Asterism::Chain::const_iterator iter = chain.begin();
01466 iter != chain.end(); iter++)
01467 glVertex(*iter);
01468 glEnd();
01469 }
01470 }
01471
01472 if ((renderFlags & ShowSmoothLines) != 0)
01473 disableSmoothLines();
01474 }
01475
01476 if ((renderFlags & ShowBoundaries) != 0)
01477 {
01478 glColor4f(0.8f, 0.33f, 0.63f, 0.35f);
01479 glDisable(GL_TEXTURE_2D);
01480 if ((renderFlags & ShowSmoothLines) != 0)
01481 enableSmoothLines();
01482 if (universe.getBoundaries() != NULL)
01483 universe.getBoundaries()->render();
01484 if ((renderFlags & ShowSmoothLines) != 0)
01485 disableSmoothLines();
01486 }
01487
01488 if ((labelMode & StarLabels) != 0 && universe.getStarCatalog() != NULL)
01489 labelStars(labelledStars, *universe.getStarCatalog(), observer);
01490 if ((labelMode & ConstellationLabels) != 0 &&
01491 universe.getAsterisms() != NULL)
01492 labelConstellations(*universe.getAsterisms(), observer);
01493
01494 glPopMatrix();
01495
01496
01497 if ((renderFlags & ShowOrbits) != 0 && orbitMask != 0)
01498 {
01499
01500
01501
01502 vector<CachedOrbit*>::const_iterator iter;
01503 for (iter = orbitCache.begin(); iter != orbitCache.end(); iter++)
01504 (*iter)->keep = false;
01505
01506 glDisable(GL_LIGHTING);
01507 glDisable(GL_TEXTURE_2D);
01508 if ((renderFlags & ShowSmoothLines) != 0)
01509 enableSmoothLines();
01510
01511 for (vector<const Star*>::const_iterator starIter = nearStars.begin();
01512 starIter != nearStars.end(); starIter++)
01513 {
01514 const Star* sun = *starIter;
01515 SolarSystem* solarSystem = universe.getSolarSystem(sun);
01516
01517 if (solarSystem != NULL)
01518 {
01519 Point3d obsPos = astrocentricPosition(observer.getPosition(),
01520 *sun, observer.getTime());
01521 glPushMatrix();
01522 glTranslatef((float) astro::kilometersToAU(-obsPos.x),
01523 (float) astro::kilometersToAU(-obsPos.y),
01524 (float) astro::kilometersToAU(-obsPos.z));
01525 renderOrbits(solarSystem->getPlanets(), sel, now,
01526 obsPos, Point3d(0.0, 0.0, 0.0));
01527 glPopMatrix();
01528 }
01529 }
01530
01531 if ((renderFlags & ShowSmoothLines) != 0)
01532 disableSmoothLines();
01533
01534
01535 for (iter = orbitCache.begin(); iter != orbitCache.end(); iter++)
01536 {
01537 if (!(*iter)->keep)
01538 (*iter)->body = NULL;
01539 }
01540 }
01541
01542 renderLabels();
01543
01544 glPolygonMode(GL_FRONT, (GLenum) renderMode);
01545 glPolygonMode(GL_BACK, (GLenum) renderMode);
01546
01547 {
01548 Frustum frustum(degToRad(fov),
01549 (float) windowWidth / (float) windowHeight,
01550 MinNearPlaneDistance);
01551 Mat3f viewMat = conjugate(observer.getOrientation()).toMatrix3();
01552
01553
01554
01555 vector<RenderListEntry>::iterator notCulled = renderList.begin();
01556 for (vector<RenderListEntry>::iterator iter = renderList.begin();
01557 iter != renderList.end(); iter++)
01558 {
01559 Point3f center = iter->position * viewMat;
01560
01561 bool convex = true;
01562 float radius = 1.0f;
01563 float cullRadius = 1.0f;
01564 float cloudHeight = 0.0f;
01565 if (iter->body != NULL)
01566 {
01567 radius = iter->body->getBoundingRadius();
01568 if (iter->body->getRings() != NULL)
01569 {
01570 radius = iter->body->getRings()->outerRadius;
01571 convex = false;
01572 }
01573
01574 if (iter->body->getModel() != InvalidResource)
01575 convex = false;
01576
01577 cullRadius = radius;
01578 if (iter->body->getAtmosphere() != NULL)
01579 {
01580 cullRadius += iter->body->getAtmosphere()->height;
01581 cloudHeight = iter->body->getAtmosphere()->cloudHeight;
01582 }
01583 }
01584 else if (iter->star != NULL)
01585 {
01586 radius = iter->star->getRadius();
01587 cullRadius = radius * (1.0f + CoronaHeight);
01588 }
01589
01590
01591 if (frustum.testSphere(center, cullRadius) != Frustum::Outside)
01592 {
01593 float nearZ = center.distanceFromOrigin() - radius;
01594 float maxSpan = (float) sqrt(square((float) windowWidth) +
01595 square((float) windowHeight));
01596
01597 nearZ = -nearZ * (float) cos(degToRad(fov / 2)) *
01598 ((float) windowHeight / maxSpan);
01599
01600 if (nearZ > -MinNearPlaneDistance)
01601 iter->nearZ = -MinNearPlaneDistance;
01602 else
01603 iter->nearZ = nearZ;
01604
01605 if (!convex)
01606 {
01607 iter->farZ = center.z - radius;
01608 if (iter->farZ / iter->nearZ > MaxFarNearRatio)
01609 iter->nearZ = iter->farZ / MaxFarNearRatio;
01610 }
01611 else
01612 {
01613
01614 float d = center.distanceFromOrigin();
01615
01616
01617 float eradius = radius;
01618 if (iter->body != NULL)
01619 eradius *= 1.0f - iter->body->getOblateness();
01620
01621 if (d > eradius)
01622 {
01623
01624
01625 iter->farZ = (float) (sqrt(square(d) -
01626 square(eradius)) * -1.1);
01627 }
01628 else
01629 {
01630
01631
01632 iter->farZ = iter->nearZ * 2.0f;
01633 }
01634
01635 if (cloudHeight > 0.0f && d < eradius + cloudHeight)
01636 {
01637
01638
01639 float cloudLayerRadius = eradius + cloudHeight;
01640 iter->farZ -= (float) sqrt(square(cloudLayerRadius) -
01641 square(eradius));
01642 }
01643 }
01644
01645 *notCulled = *iter;
01646 notCulled++;
01647 }
01648 }
01649
01650 renderList.resize(notCulled - renderList.begin());
01651
01652
01653
01654
01655 stable_sort(renderList.begin(), renderList.end());
01656
01657
01658 sort(depthSortedLabels.begin(), depthSortedLabels.end());
01659
01660 int nEntries = renderList.size();
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672 int nDepthBuckets = 1;
01673 int i;
01674 {
01675 float lastNear = 0.0f;
01676 float lastFar = 0.0f;
01677 int firstCoalesced = 0;
01678
01679 for (i = 0; i < nEntries; i++)
01680 {
01681
01682
01683 if (renderList[i].discSizeInPixels > 1)
01684 {
01685 if (nDepthBuckets == 1 || renderList[i].nearZ <= lastFar)
01686 {
01687
01688
01689 nDepthBuckets++;
01690 firstCoalesced = i;
01691 lastNear = renderList[i].nearZ;
01692 lastFar = renderList[i].farZ;
01693 }
01694 else
01695 {
01696
01697
01698 float farthest = min(lastFar, renderList[i].farZ);
01699 float nearest = max(lastNear, renderList[i].nearZ);
01700 static int blah = 0;
01701
01702
01703
01704 if (farthest / nearest < MaxFarNearRatio * 1.01f)
01705 {
01706
01707
01708
01709 for (int j = firstCoalesced; j <= i; j++)
01710 {
01711 renderList[j].farZ = farthest;
01712 renderList[j].nearZ = nearest;
01713 }
01714 #if DEBUG_COALESCE
01715 clog << "Coalesce #" << i << ": " <<
01716 renderList[i].body->getName() << ", " <<
01717 nearest << ", " << farthest << " -- " << blah++ << '\n';
01718 #endif
01719 lastNear = nearest;
01720 lastFar = farthest;
01721 }
01722 else
01723 {
01724
01725
01726 nDepthBuckets++;
01727 firstCoalesced = i;
01728 lastNear = renderList[i].nearZ;
01729 lastFar = renderList[i].farZ;
01730 #if DEBUG_COALESCE
01731 clog << "Coalesce #" << i << ": " <<
01732 renderList[i].body->getName() << " failed! " <<
01733 nearest << ", " << farthest << " -- " << blah++ << '\n';
01734 #endif
01735 }
01736 }
01737 renderList[i].depthBucket = nDepthBuckets - 1;
01738 }
01739 }
01740 }
01741
01742 float depthRange = 1.0f / (float) nDepthBuckets;
01743
01744 int depthBucket = nDepthBuckets - 1;
01745 i = nEntries - 1;
01746
01747
01748 glDepthRange(depthBucket * depthRange, (depthBucket + 1) * depthRange);
01749
01750
01751
01752
01753 float nearPlaneDistance = 1.0f;
01754 float farPlaneDistance = 10.0f;
01755 glMatrixMode(GL_PROJECTION);
01756 glLoadIdentity();
01757 gluPerspective(fov, (float) windowWidth / (float) windowHeight,
01758 nearPlaneDistance, farPlaneDistance);
01759 glMatrixMode(GL_MODELVIEW);
01760
01761 vector<Label>::iterator label = depthSortedLabels.begin();
01762
01763
01764 for (i = nEntries - 1; i >= 0; i--)
01765 {
01766 label = renderSortedLabels(label, -renderList[i].farZ);
01767
01768 if (renderList[i].discSizeInPixels > 1)
01769 {
01770 depthBucket = renderList[i].depthBucket;
01771 glDepthRange(depthBucket * depthRange, (depthBucket + 1) * depthRange);
01772
01773 nearPlaneDistance = renderList[i].nearZ * -0.9f;
01774 farPlaneDistance = renderList[i].farZ * -1.5f;
01775 if (nearPlaneDistance < MinNearPlaneDistance)
01776 nearPlaneDistance = MinNearPlaneDistance;
01777 if (farPlaneDistance / nearPlaneDistance > MaxFarNearRatio)
01778 farPlaneDistance = nearPlaneDistance * MaxFarNearRatio;
01779
01780 glMatrixMode(GL_PROJECTION);
01781 glLoadIdentity();
01782 gluPerspective(fov, (float) windowWidth / (float) windowHeight,
01783 nearPlaneDistance, farPlaneDistance);
01784 glMatrixMode(GL_MODELVIEW);
01785 }
01786
01787 if (renderList[i].body != NULL)
01788 {
01789 if (renderList[i].isCometTail)
01790 {
01791 renderCometTail(*renderList[i].body,
01792 renderList[i].position,
01793 renderList[i].distance,
01794 renderList[i].appMag,
01795 now,
01796 observer.getOrientation(),
01797 lightSourceLists[renderList[i].solarSysIndex],
01798 nearPlaneDistance, farPlaneDistance);
01799 }
01800 else
01801 {
01802 renderPlanet(*renderList[i].body,
01803 renderList[i].position,
01804 renderList[i].distance,
01805 renderList[i].appMag,
01806 now,
01807 observer.getOrientation(),
01808 lightSourceLists[renderList[i].solarSysIndex],
01809 nearPlaneDistance, farPlaneDistance);
01810
01811 renderForegroundOrbits(renderList[i].body->getSatellites(),
01812 renderList[i].position,
01813 renderList[i].distance,
01814 renderList[i].discSizeInPixels,
01815 sel,
01816 now);
01817 }
01818 }
01819 else if (renderList[i].star != NULL)
01820 {
01821 renderStar(*renderList[i].star,
01822 renderList[i].position,
01823 renderList[i].distance,
01824 renderList[i].appMag,
01825 observer.getOrientation(),
01826 now,
01827 nearPlaneDistance, farPlaneDistance);
01828 }
01829
01830
01831
01832
01833 if (renderList[i].discSizeInPixels > 1)
01834 {
01835 depthBucket--;
01836 glDepthRange(depthBucket * depthRange, (depthBucket + 1) * depthRange);
01837 }
01838 }
01839
01840 renderSortedLabels(label, 0.0f);
01841
01842
01843 glDepthRange(0, 1);
01844 }
01845
01846 glPopMatrix();
01847
01848 glEnable(GL_TEXTURE_2D);
01849 glDisable(GL_LIGHTING);
01850 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01851
01852 glPolygonMode(GL_FRONT, GL_FILL);
01853 glPolygonMode(GL_BACK, GL_FILL);
01854
01855 {
01856 Mat3f m = observer.getOrientation().toMatrix3();
01857 for (int i = 0; i < (int) labels.size(); i++)
01858 {
01859
01860 }
01861 }
01862
01863 if ((renderFlags & ShowMarkers) != 0)
01864 {
01865 renderMarkers(*universe.getMarkers(),
01866 observer.getPosition(),
01867 observer.getOrientation(),
01868 now);
01869 }
01870
01871 glDisable(GL_BLEND);
01872 glDepthMask(GL_TRUE);
01873 glEnable(GL_LIGHTING);
01874
01875 #if 0
01876 int errCode = glGetError();
01877 if (errCode != GL_NO_ERROR)
01878 {
01879 cout << "glError: " << (char*) gluErrorString(errCode) << '\n';
01880 }
01881 #endif
01882 }
01883
01884
01885 static void renderRingSystem(float innerRadius,
01886 float outerRadius,
01887 float beginAngle,
01888 float endAngle,
01889 unsigned int nSections)
01890 {
01891 float angle = endAngle - beginAngle;
01892
01893 glBegin(GL_QUAD_STRIP);
01894 for (unsigned int i = 0; i <= nSections; i++)
01895 {
01896 float t = (float) i / (float) nSections;
01897 float theta = beginAngle + t * angle;
01898 float s = (float) sin(theta);
01899 float c = (float) cos(theta);
01900 glTexCoord2f(0, 0.5f);
01901 glVertex3f(c * innerRadius, 0, s * innerRadius);
01902 glTexCoord2f(1, 0.5f);
01903 glVertex3f(c * outerRadius, 0, s * outerRadius);
01904 }
01905 glEnd();
01906 }
01907
01908
01909
01910
01911
01912
01913
01914
01915 void Renderer::renderBodyAsParticle(Point3f position,
01916 float appMag,
01917 float _faintestMag,
01918 float discSizeInPixels,
01919 Color color,
01920 const Quatf& orientation,
01921 float renderZ,
01922 bool useHaloes)
01923 {
01924 float maxDiscSize = (starStyle == ScaledDiscStars) ? MaxScaledDiscStarSize : 1.0f;
01925 float maxBlendDiscSize = maxDiscSize + 3.0f;
01926 float discSize = 1.0f;
01927
01928 if (discSizeInPixels < maxBlendDiscSize || useHaloes)
01929 {
01930 float a = 1;
01931 float fade = 1.0f;
01932
01933 if (discSizeInPixels > maxDiscSize)
01934 {
01935 fade = (maxBlendDiscSize - discSizeInPixels) /
01936 (maxBlendDiscSize - maxDiscSize - 1.0f);
01937 if (fade > 1)
01938 fade = 1;
01939 }
01940
01941 a = (_faintestMag - appMag) * brightnessScale + brightnessBias;
01942 if (starStyle == ScaledDiscStars && a > 1.0f)
01943 discSize = min(discSize * (2.0f * a - 1.0f), maxDiscSize);
01944 a = clamp(a) * fade;
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957 float size = discSize * pixelSize * 1.6f * renderZ / corrFac;
01958 float posScale = abs(renderZ / (position * conjugate(orientation).toMatrix3()).z);
01959
01960 Point3f center(position.x * posScale,
01961 position.y * posScale,
01962 position.z * posScale);
01963 Mat3f m = orientation.toMatrix3();
01964 Vec3f v0 = Vec3f(-1, -1, 0) * m;
01965 Vec3f v1 = Vec3f( 1, -1, 0) * m;
01966 Vec3f v2 = Vec3f( 1, 1, 0) * m;
01967 Vec3f v3 = Vec3f(-1, 1, 0) * m;
01968
01969 starTex->bind();
01970 glColor(color, a);
01971 glBegin(GL_QUADS);
01972 glTexCoord2f(0, 0);
01973 glVertex(center + (v0 * size));
01974 glTexCoord2f(1, 0);
01975 glVertex(center + (v1 * size));
01976 glTexCoord2f(1, 1);
01977 glVertex(center + (v2 * size));
01978 glTexCoord2f(0, 1);
01979 glVertex(center + (v3 * size));
01980 glEnd();
01981
01982
01983
01984
01985
01986
01987
01988 if (useHaloes && appMag < saturationMag)
01989 {
01990 a = 0.4f * clamp((appMag - saturationMag) * -0.8f);
01991 float s = renderZ * 0.001f * (3 - (appMag - saturationMag)) * 2;
01992 if (s > size * 3)
01993 size = s * 2.0f/(1.0f +FOV/fov);
01994 else
01995 size = size * 3;
01996 float realSize = discSizeInPixels * pixelSize * renderZ;
01997 if (size < realSize * 10)
01998 size = realSize * 10;
01999 glareTex->bind();
02000 glColor(color, a);
02001 glBegin(GL_QUADS);
02002 glTexCoord2f(0, 0);
02003 glVertex(center + (v0 * size));
02004 glTexCoord2f(1, 0);
02005 glVertex(center + (v1 * size));
02006 glTexCoord2f(1, 1);
02007 glVertex(center + (v2 * size));
02008 glTexCoord2f(0, 1);
02009 glVertex(center + (v3 * size));
02010 glEnd();
02011 }
02012 }
02013 }
02014
02015
02016 static void renderBumpMappedMesh(const GLContext& context,
02017 Texture& baseTexture,
02018 Texture& bumpTexture,
02019 Vec3f lightDirection,
02020 Quatf orientation,
02021 Color ambientColor,
02022 const Frustum& frustum,
02023 float lod)
02024 {
02025
02026 glDisable(GL_LIGHTING);
02027
02028
02029
02030 lodSphere->render(context,
02031 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
02032 frustum, lod,
02033 &baseTexture);
02034
02035
02036
02037
02038 Quatf lightOrientation;
02039 {
02040 Vec3f zeroLightDirection(0, 0, 1);
02041 Vec3f axis = lightDirection ^ zeroLightDirection;
02042 float cosAngle = zeroLightDirection * lightDirection;
02043 float angle = 0.0f;
02044 float epsilon = 1e-5f;
02045
02046 if (cosAngle + 1 < epsilon)
02047 {
02048 axis = Vec3f(0, 1, 0);
02049 angle = (float) PI;
02050 }
02051 else if (cosAngle - 1 > -epsilon)
02052 {
02053 axis = Vec3f(0, 1, 0);
02054 angle = 0.0f;
02055 }
02056 else
02057 {
02058 axis.normalize();
02059 angle = (float) acos(cosAngle);
02060 }
02061 lightOrientation.setAxisAngle(axis, angle);
02062 }
02063
02064 glEnable(GL_BLEND);
02065 glBlendFunc(GL_DST_COLOR, GL_ZERO);
02066
02067
02068 SetupCombinersBumpMap(bumpTexture, *normalizationTex, ambientColor);
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
02079
02080
02081
02082 glEnable(GL_TEXTURE_GEN_R);
02083 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT);
02084 glEnable(GL_TEXTURE_GEN_S);
02085 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT);
02086 glEnable(GL_TEXTURE_GEN_T);
02087 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT);
02088
02089
02090
02091 glMatrixMode(GL_TEXTURE);
02092 glScalef(-1.0f, 1.0f, 1.0f);
02093 glRotate(lightOrientation * ~orientation);
02094 glMatrixMode(GL_MODELVIEW);
02095 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
02096
02097 lodSphere->render(context,
02098 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
02099 frustum, lod,
02100 &bumpTexture);
02101
02102
02103 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
02104 glMatrixMode(GL_TEXTURE);
02105 glLoadIdentity();
02106 glMatrixMode(GL_MODELVIEW);
02107 glDisable(GL_TEXTURE_GEN_R);
02108 glDisable(GL_TEXTURE_GEN_S);
02109 glDisable(GL_TEXTURE_GEN_T);
02110
02111 DisableCombiners();
02112 glDisable(GL_BLEND);
02113 }
02114
02115
02116 static void renderSmoothMesh(const GLContext& context,
02117 Texture& baseTexture,
02118 Vec3f lightDirection,
02119 Quatf orientation,
02120 Color ambientColor,
02121 float lod,
02122 const Frustum& frustum,
02123 bool invert = false)
02124 {
02125 Texture* textures[4];
02126
02127
02128 glDisable(GL_LIGHTING);
02129
02130
02131
02132
02133 Quatf lightOrientation;
02134 {
02135 Vec3f zeroLightDirection(0, 0, 1);
02136 Vec3f axis = lightDirection ^ zeroLightDirection;
02137 float cosAngle = zeroLightDirection * lightDirection;
02138 float angle = 0.0f;
02139 float epsilon = 1e-5f;
02140
02141 if (cosAngle + 1 < epsilon)
02142 {
02143 axis = Vec3f(0, 1, 0);
02144 angle = (float) PI;
02145 }
02146 else if (cosAngle - 1 > -epsilon)
02147 {
02148 axis = Vec3f(0, 1, 0);
02149 angle = 0.0f;
02150 }
02151 else
02152 {
02153 axis.normalize();
02154 angle = (float) acos(cosAngle);
02155 }
02156 lightOrientation.setAxisAngle(axis, angle);
02157 }
02158
02159 SetupCombinersSmooth(baseTexture, *normalizationTex, ambientColor, invert);
02160
02161
02162
02163
02164
02165
02166
02167
02168
02169 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
02170
02171
02172
02173 glEnable(GL_TEXTURE_GEN_R);
02174 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT);
02175 glEnable(GL_TEXTURE_GEN_S);
02176 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT);
02177 glEnable(GL_TEXTURE_GEN_T);
02178 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_EXT);
02179
02180
02181
02182 glMatrixMode(GL_TEXTURE);
02183 glRotate(lightOrientation * ~orientation);
02184 glMatrixMode(GL_MODELVIEW);
02185 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
02186
02187 textures[0] = &baseTexture;
02188 lodSphere->render(context,
02189 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
02190 frustum, lod,
02191 textures, 1);
02192
02193
02194 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
02195 glMatrixMode(GL_TEXTURE);
02196 glLoadIdentity();
02197 glMatrixMode(GL_MODELVIEW);
02198 glDisable(GL_TEXTURE_GEN_R);
02199 glDisable(GL_TEXTURE_GEN_S);
02200 glDisable(GL_TEXTURE_GEN_T);
02201
02202 DisableCombiners();
02203 }
02204
02205
02206 struct RenderInfo
02207 {
02208 Color color;
02209 Texture* baseTex;
02210 Texture* bumpTex;
02211 Texture* nightTex;
02212 Texture* glossTex;
02213 Texture* overlayTex;
02214 Color hazeColor;
02215 Color specularColor;
02216 float specularPower;
02217 Vec3f sunDir_eye;
02218 Vec3f sunDir_obj;
02219 Vec3f eyeDir_obj;
02220 Point3f eyePos_obj;
02221 Color sunColor;
02222 Color ambientColor;
02223 Quatf orientation;
02224 float pixWidth;
02225 bool useTexEnvCombine;
02226
02227 RenderInfo() : color(1.0f, 1.0f, 1.0f),
02228 baseTex(NULL),
02229 bumpTex(NULL),
02230 nightTex(NULL),
02231 glossTex(NULL),
02232 overlayTex(NULL),
02233 hazeColor(0.0f, 0.0f, 0.0f),
02234 specularColor(0.0f, 0.0f, 0.0f),
02235 specularPower(0.0f),
02236 sunDir_eye(0.0f, 0.0f, 1.0f),
02237 sunDir_obj(0.0f, 0.0f, 1.0f),
02238 eyeDir_obj(0.0f, 0.0f, 1.0f),
02239 eyePos_obj(0.0f, 0.0f, 0.0f),
02240 sunColor(1.0f, 1.0f, 1.0f),
02241 ambientColor(0.0f, 0.0f, 0.0f),
02242 orientation(1.0f, 0.0f, 0.0f, 0.0f),
02243 pixWidth(1.0f),
02244 useTexEnvCombine(false)
02245 {};
02246 };
02247
02248
02249
02250 struct LightIrradiancePredicate
02251 {
02252 int unused;
02253
02254 LightIrradiancePredicate() {};
02255
02256 bool operator()(const DirectionalLight& l0,
02257 const DirectionalLight& l1) const
02258 {
02259 return (l0.irradiance > l1.irradiance);
02260 }
02261 };
02262
02263
02264 void renderAtmosphere(const Atmosphere& atmosphere,
02265 Point3f center,
02266 float radius,
02267 const Vec3f& sunDirection,
02268 Color ambientColor,
02269 float fade,
02270 bool lit)
02271 {
02272 if (atmosphere.height == 0.0f)
02273 return;
02274
02275 glDepthMask(GL_FALSE);
02276
02277 Vec3f eyeVec = center - Point3f(0.0f, 0.0f, 0.0f);
02278 double centerDist = eyeVec.length();
02279
02280
02281 Vec3f normal = eyeVec;
02282 normal = normal / (float) centerDist;
02283
02284 float tangentLength = (float) sqrt(square(centerDist) - square(radius));
02285 float atmRadius = tangentLength * radius / (float) centerDist;
02286 float atmOffsetFromCenter = square(radius) / (float) centerDist;
02287 Point3f atmCenter = center - atmOffsetFromCenter * normal;
02288
02289 Vec3f uAxis, vAxis;
02290 if (abs(normal.x) < abs(normal.y) && abs(normal.x) < abs(normal.z))
02291 {
02292 uAxis = Vec3f(1, 0, 0) ^ normal;
02293 uAxis.normalize();
02294 }
02295 else if (abs(eyeVec.y) < abs(normal.z))
02296 {
02297 uAxis = Vec3f(0, 1, 0) ^ normal;
02298 uAxis.normalize();
02299 }
02300 else
02301 {
02302 uAxis = Vec3f(0, 0, 1) ^ normal;
02303 uAxis.normalize();
02304 }
02305 vAxis = uAxis ^ normal;
02306
02307 float height = atmosphere.height / radius;
02308
02309 glBegin(GL_QUAD_STRIP);
02310 int divisions = 180;
02311 for (int i = 0; i <= divisions; i++)
02312 {
02313 float theta = (float) i / (float) divisions * 2 * (float) PI;
02314 Vec3f v = (float) cos(theta) * uAxis + (float) sin(theta) * vAxis;
02315 Point3f base = atmCenter + v * atmRadius;
02316 Vec3f toCenter = base - center;
02317
02318 float cosSunAngle = (toCenter * sunDirection) / radius;
02319 float brightness = 1.0f;
02320 float botColor[3];
02321 float topColor[3];
02322 botColor[0] = atmosphere.lowerColor.red();
02323 botColor[1] = atmosphere.lowerColor.green();
02324 botColor[2] = atmosphere.lowerColor.blue();
02325 topColor[0] = atmosphere.upperColor.red();
02326 topColor[1] = atmosphere.upperColor.green();
02327 topColor[2] = atmosphere.upperColor.blue();
02328
02329 if (cosSunAngle < 0.2f && lit)
02330 {
02331 if (cosSunAngle < -0.2f)
02332 {
02333 brightness = 0;
02334 }
02335 else
02336 {
02337 float t = (0.2f + cosSunAngle) * 2.5f;
02338 brightness = t;
02339 botColor[0] = Mathf::lerp(t, 1.0f, botColor[0]);
02340 botColor[1] = Mathf::lerp(t, 0.3f, botColor[1]);
02341 botColor[2] = Mathf::lerp(t, 0.0f, botColor[2]);
02342 topColor[0] = Mathf::lerp(t, 1.0f, topColor[0]);
02343 topColor[1] = Mathf::lerp(t, 0.3f, topColor[1]);
02344 topColor[2] = Mathf::lerp(t, 0.0f, topColor[2]);
02345 }
02346 }
02347
02348 glColor4f(botColor[0], botColor[1], botColor[2],
02349 0.85f * fade * brightness + ambientColor.red());
02350 glVertex(base - toCenter * height * 0.05f);
02351 glColor4f(topColor[0], topColor[1], topColor[2], 0.0f);
02352 glVertex(base + toCenter * height);
02353 }
02354 glEnd();
02355 }
02356
02357
02358 static Vec3f ellipsoidTangent(const Vec3f& recipSemiAxes,
02359 const Vec3f& w,
02360 const Vec3f& e,
02361 const Vec3f& e_,
02362 float ee)
02363 {
02364
02365
02366
02367
02368
02369
02370 Vec3f w_(w.x * recipSemiAxes.x, w.y * recipSemiAxes.y, w.z * recipSemiAxes.z);
02371 float ww = w_ * w_;
02372 float ew = w_ * e_;
02373
02374
02375
02376
02377
02378
02379 float a = 4 * square(ee + ew) - 4 * (ee + 2 * ew + ww) * (ee - 1.0f);
02380 float b = -8 * (ee + ew);
02381 float c = 4 * ee;
02382
02383 float t = 0.0f;
02384 float discriminant = b * b - 4 * a * c;
02385
02386 if (discriminant < 0.0f)
02387 t = (-b + (float) sqrt(-discriminant)) / (2 * a);
02388 else
02389 t = (-b + (float) sqrt(discriminant)) / (2 * a);
02390
02391
02392
02393
02394
02395 Vec3f v = -e * (1 - t) + w * t;
02396 Vec3f v_(v.x * recipSemiAxes.x, v.y * recipSemiAxes.y, v.z * recipSemiAxes.z);
02397 float a1 = v_ * v_;
02398 float b1 = 2.0f * v_ * e_;
02399 float t1 = -b1 / (2 * a1);
02400
02401 return e + v * t1;
02402 }
02403
02404
02405 void Renderer::renderEllipsoidAtmosphere(const Atmosphere& atmosphere,
02406 Point3f center,
02407 const Quatf& orientation,
02408 Vec3f semiAxes,
02409 const Vec3f& sunDirection,
02410 Color ambientColor,
02411 float pixSize,
02412 bool lit)
02413 {
02414 if (atmosphere.height == 0.0f)
02415 return;
02416
02417 glDepthMask(GL_FALSE);
02418
02419
02420
02421 float fade = clamp(pixSize - 2);
02422
02423 Mat3f rot = orientation.toMatrix3();
02424 Mat3f irot = conjugate(orientation).toMatrix3();
02425
02426 Point3f eyePos(0.0f, 0.0f, 0.0f);
02427 float radius = max(semiAxes.x, max(semiAxes.y, semiAxes.z));
02428 Vec3f eyeVec = center - eyePos;
02429 eyeVec = eyeVec * irot;
02430 double centerDist = eyeVec.length();
02431
02432 float height = atmosphere.height / radius;
02433 Vec3f recipSemiAxes(1.0f / semiAxes.x, 1.0f / semiAxes.y, 1.0f / semiAxes.z);
02434
02435 Vec3f recipAtmSemiAxes = recipSemiAxes / (1.0f + height);
02436 Mat3f A = Mat3f::scaling(recipAtmSemiAxes);
02437 Mat3f A1 = Mat3f::scaling(recipSemiAxes);
02438
02439
02440
02441
02442
02443
02444
02445
02446 float ellipDist = (float) sqrt((eyeVec * A1) * (eyeVec * A1)) - 1.0f;
02447 bool within = ellipDist < height;
02448
02449
02450
02451 int nSlices = MaxSkySlices;
02452 if (ellipDist < 0.25f)
02453 {
02454 nSlices = MinSkySlices + max(0, (int) ((ellipDist / 0.25f) * (MaxSkySlices - MinSkySlices)));
02455 nSlices &= ~1;
02456 }
02457
02458 int nRings = min(1 + (int) pixSize / 5, 6);
02459 int nHorizonRings = nRings;
02460 if (within)
02461 nRings += 12;
02462
02463 float horizonHeight = height;
02464 if (within)
02465 {
02466 if (ellipDist <= 0.0f)
02467 horizonHeight = 0.0f;
02468 else
02469 horizonHeight *= max((float) pow(ellipDist / height, 0.33f), 0.001f);
02470 }
02471
02472 Vec3f e = -eyeVec;
02473 Vec3f e_(e.x * recipSemiAxes.x, e.y * recipSemiAxes.y, e.z * recipSemiAxes.z);
02474 float ee = e_ * e_;
02475
02476
02477
02478 float cosSunAltitude = 0.0f;
02479 {
02480
02481 float cosSunAngle = (float) ((sunDirection * e) / centerDist);
02482 if (cosSunAngle < -1.0f + 1.0e-6f)
02483 {
02484 cosSunAltitude = 0.0f;
02485 }
02486 else if (cosSunAngle > 1.0f - 1.0e-6f)
02487 {
02488 cosSunAltitude = 0.0f;
02489 }
02490 else
02491 {
02492 Point3f tangentPoint = center +
02493 ellipsoidTangent(recipSemiAxes,
02494 (-sunDirection * irot) * (float) centerDist,
02495 e, e_, ee) * rot;
02496 Vec3f tangentDir = tangentPoint - eyePos;
02497 tangentDir.normalize();
02498 cosSunAltitude = sunDirection * tangentDir;
02499 }
02500 }
02501
02502 Vec3f normal = eyeVec;
02503 normal = normal / (float) centerDist;
02504
02505 Vec3f uAxis, vAxis;
02506 if (abs(normal.x) < abs(normal.y) && abs(normal.x) < abs(normal.z))
02507 {
02508 uAxis = Vec3f(1, 0, 0) ^ normal;
02509 uAxis.normalize();
02510 }
02511 else if (abs(eyeVec.y) < abs(normal.z))
02512 {
02513 uAxis = Vec3f(0, 1, 0) ^ normal;
02514 uAxis.normalize();
02515 }
02516 else
02517 {
02518 uAxis = Vec3f(0, 0, 1) ^ normal;
02519 uAxis.normalize();
02520 }
02521 vAxis = uAxis ^ normal;
02522
02523
02524 int i;
02525 for (i = 0; i <= nSlices; i++)
02526 {
02527
02528
02529 float theta = (float) i / (float) nSlices * 2 * (float) PI;
02530 Vec3f w = (float) cos(theta) * uAxis + (float) sin(theta) * vAxis;
02531 w = w * (float) centerDist;
02532
02533 Vec3f toCenter = ellipsoidTangent(recipSemiAxes, w, e, e_, ee);
02534 skyContour[i].v = toCenter * rot;
02535 skyContour[i].centerDist = skyContour[i].v.length();
02536 skyContour[i].eyeDir = skyContour[i].v + (center - eyePos);
02537 skyContour[i].eyeDist = skyContour[i].eyeDir.length();
02538 skyContour[i].eyeDir.normalize();
02539
02540 float skyCapDist = (float) sqrt(square(skyContour[i].eyeDist) +
02541 square(horizonHeight * radius));
02542 skyContour[i].cosSkyCapAltitude = skyContour[i].eyeDist /
02543 skyCapDist;
02544 }
02545
02546
02547 Vec3f botColor(atmosphere.lowerColor.red(),
02548 atmosphere.lowerColor.green(),
02549 atmosphere.lowerColor.blue());
02550 Vec3f topColor(atmosphere.upperColor.red(),
02551 atmosphere.upperColor.green(),
02552 atmosphere.upperColor.blue());
02553 Vec3f sunsetColor(atmosphere.sunsetColor.red(),
02554 atmosphere.sunsetColor.green(),
02555 atmosphere.sunsetColor.blue());
02556 if (within)
02557 {
02558 Vec3f skyColor(atmosphere.skyColor.red(),
02559 atmosphere.skyColor.green(),
02560 atmosphere.skyColor.blue());
02561 if (ellipDist < 0.0f)
02562 topColor = skyColor;
02563 else
02564 topColor = skyColor + (topColor - skyColor) * (ellipDist / height);
02565 }
02566
02567 Vec3f zenith = (skyContour[0].v + skyContour[nSlices / 2].v);
02568 zenith.normalize();
02569 zenith *= skyContour[0].centerDist * (1.0f + horizonHeight * 2.0f);
02570
02571 float minOpacity = within ? (1.0f - ellipDist / height) * 0.75f : 0.0f;
02572 float sunset = cosSunAltitude < 0.9f ? 0.0f : (cosSunAltitude - 0.9f) * 10.0f;
02573
02574
02575 SkyVertex* vtx = skyVertices;
02576 for (i = 0; i <= nRings; i++)
02577 {
02578 float h = min(1.0f, (float) i / (float) nHorizonRings);
02579 float hh = (float) sqrt(h);
02580 float u = i <= nHorizonRings ? 0.0f :
02581 (float) (i - nHorizonRings) / (float) (nRings - nHorizonRings);
02582 float r = Mathf::lerp(h, 1.0f - (horizonHeight * 0.05f), 1.0f + horizonHeight);
02583 float atten = 1.0f - hh;
02584
02585 for (int j = 0; j < nSlices; j++)
02586 {
02587 Vec3f v;
02588 if (i <= nHorizonRings)
02589 v = skyContour[j].v * r;
02590 else
02591 v = (skyContour[j].v * (1.0f - u) + zenith * u) * r;
02592 Point3f p = center + v;
02593
02594
02595 Vec3f viewDir(p.x, p.y, p.z);
02596 viewDir.normalize();
02597 float cosSunAngle = viewDir * sunDirection;
02598 float cosAltitude = viewDir * skyContour[j].eyeDir;
02599 float brightness = 1.0f;
02600 float coloration = 0.0f;
02601 if (lit)
02602 {
02603 if (sunset > 0.0f && cosSunAngle > 0.7f && cosAltitude > 0.98f)
02604 {
02605 coloration = (1.0f / 0.30f) * (cosSunAngle - 0.70f);
02606 coloration *= 50.0f * (cosAltitude - 0.98f);
02607 coloration *= sunset;
02608 }
02609
02610 cosSunAngle = (skyContour[j].v * sunDirection) / skyContour[j].centerDist;
02611 if (cosSunAngle > -0.2f)
02612 {
02613 if (cosSunAngle < 0.3f)
02614 brightness = (cosSunAngle + 0.2f) * 2.0f;
02615 else
02616 brightness = 1.0f;
02617 }
02618 else
02619 {
02620 brightness = 0.0f;
02621 }
02622 }
02623
02624 vtx->x = p.x;
02625 vtx->y = p.y;
02626 vtx->z = p.z;
02627
02628 #if 0
02629
02630
02631 if (!within)
02632 {
02633 hh = (1.0f - cosAltitude) / (1.0f - skyContour[j].cosSkyCapAltitude);
02634 }
02635 else
02636 {
02637 float top = pow((ellipDist / height), 0.125f) * skyContour[j].cosSkyCapAltitude;
02638 if (cosAltitude < top)
02639 hh = 1.0f;
02640 else
02641 hh = (1.0f - cosAltitude) / (1.0f - top);
02642 }
02643 hh = sqrt(hh);
02644
02645 #endif
02646
02647 atten = 1.0f - hh;
02648 Vec3f color = (1.0f - hh) * botColor + hh * topColor;
02649 brightness *= minOpacity + (1.0f - minOpacity) * fade * atten;
02650 if (coloration != 0.0f)
02651 color = (1.0f - coloration) * color + coloration * sunsetColor;
02652
02653 Color(brightness * color.x,
02654 brightness * color.y,
02655 brightness * color.z,
02656 fade * (minOpacity + (1.0f - minOpacity)) * atten).get(vtx->color);
02657 vtx++;
02658 }
02659 }
02660
02661
02662 int index = 0;
02663 for (i = 0; i < nRings; i++)
02664 {
02665 int baseVertex = i * nSlices;
02666 for (int j = 0; j < nSlices; j++)
02667 {
02668 skyIndices[index++] = baseVertex + j;
02669 skyIndices[index++] = baseVertex + nSlices + j;
02670 }
02671 skyIndices[index++] = baseVertex;
02672 skyIndices[index++] = baseVertex + nSlices;
02673 }
02674
02675 glEnableClientState(GL_VERTEX_ARRAY);
02676 glVertexPointer(3, GL_FLOAT, sizeof(SkyVertex), &skyVertices[0].x);
02677 glEnableClientState(GL_COLOR_ARRAY);
02678 glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SkyVertex),
02679 static_cast<void*>(&skyVertices[0].color));
02680
02681 for (i = 0; i < nRings; i++)
02682 {
02683 glDrawElements(GL_QUAD_STRIP,
02684 (nSlices + 1) * 2,
02685 GL_UNSIGNED_INT,
02686 &skyIndices[(nSlices + 1) * 2 * i]);
02687 }
02688
02689 glDisableClientState(GL_COLOR_ARRAY);
02690 }
02691
02692
02693 void renderCompass(Point3f center,
02694 const Quatf& orientation,
02695 Vec3f semiAxes,
02696 float pixelSize)
02697 {
02698 Mat3f rot = orientation.toMatrix3();
02699 Mat3f irot = conjugate(orientation).toMatrix3();
02700
02701 Point3f eyePos(0.0f, 0.0f, 0.0f);
02702 float radius = max(semiAxes.x, max(semiAxes.y, semiAxes.z));
02703 Vec3f eyeVec = center - eyePos;
02704 eyeVec = eyeVec * irot;
02705 double centerDist = eyeVec.length();
02706
02707 float height = 1.0f / radius;
02708 Vec3f recipSemiAxes(1.0f / semiAxes.x,
02709 1.0f / semiAxes.y,
02710 1.0f / semiAxes.z);
02711
02712 Vec3f recipAtmSemiAxes = recipSemiAxes / (1.0f + height);
02713 Mat3f A = Mat3f::scaling(recipAtmSemiAxes);
02714 Mat3f A1 = Mat3f::scaling(recipSemiAxes);
02715
02716 const int nCompassPoints = 16;
02717 Vec3f compassPoints[nCompassPoints];
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727 float ellipDist = (float) sqrt((eyeVec * A1) * (eyeVec * A1)) - 1.0f;
02728
02729 Vec3f e = -eyeVec;
02730 Vec3f e_(e.x * recipSemiAxes.x, e.y * recipSemiAxes.y, e.z * recipSemiAxes.z);
02731 float ee = e_ * e_;
02732
02733 Vec3f normal = eyeVec;
02734 normal = normal / (float) centerDist;
02735
02736 Vec3f uAxis, vAxis;
02737 Vec3f northPole(0.0f, 1.0f, 0.0f);
02738 vAxis = normal ^ northPole;
02739 vAxis.normalize();
02740 uAxis = vAxis ^ normal;
02741
02742
02743 int i;
02744 for (i = 0; i < nCompassPoints; i++)
02745 {
02746
02747
02748 float theta = (float) i / (float) nCompassPoints * 2 * (float) PI;
02749 Vec3f w = (float) cos(theta) * uAxis + (float) sin(theta) * vAxis;
02750 w = w * (float) centerDist;
02751
02752 Vec3f toCenter = ellipsoidTangent(recipSemiAxes, w, e, e_, ee);
02753 compassPoints[i] = toCenter * rot;
02754 }
02755
02756 glColor(compassColor);
02757 glBegin(GL_LINES);
02758 glDisable(GL_LIGHTING);
02759 for (i = 0; i < nCompassPoints; i++)
02760 {
02761 float distance = (center + compassPoints[i]).distanceFromOrigin();
02762
02763 float length = distance * pixelSize * 8.0f;
02764 if (i % 4 == 0)
02765 length *= 3.0f;
02766 else if (i % 2 == 0)
02767 length *= 2.0f;
02768
02769 glVertex(center + compassPoints[i]);
02770 glVertex(center + compassPoints[i] * (1.0f + length));
02771 }
02772 glEnd();
02773 }
02774
02775
02776 static void setupNightTextureCombine()
02777 {
02778 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02779 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
02780 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_ONE_MINUS_SRC_COLOR);
02781 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
02782 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02783 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
02784 }
02785
02786
02787 static void setupBumpTexenv()
02788 {
02789
02790
02791 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02792
02793
02794
02795
02796 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_ARB);
02797 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
02798 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02799 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
02800 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02801
02802
02803
02804 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
02805 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
02806 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
02807 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02808 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT);
02809 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02810 glEnable(GL_TEXTURE_2D);
02811
02812 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
02813 }
02814
02815
02816 static void setupBumpTexenvAmbient(Color ambientColor)
02817 {
02818 float texenvConst[4];
02819 texenvConst[0] = ambientColor.red();
02820 texenvConst[1] = ambientColor.green();
02821 texenvConst[2] = ambientColor.blue();
02822 texenvConst[3] = ambientColor.alpha();
02823
02824
02825 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02826
02827
02828
02829
02830 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
02831 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_ARB);
02832 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
02833 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02834 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
02835 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02836
02837
02838 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
02839 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, texenvConst);
02840 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02841 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
02842 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
02843 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02844 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
02845 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02846 glEnable(GL_TEXTURE_2D);
02847
02848
02849
02850 glx::glActiveTextureARB(GL_TEXTURE2_ARB);
02851 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02852 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
02853 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
02854 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02855 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
02856 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02857 glEnable(GL_TEXTURE_2D);
02858
02859 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
02860 }
02861
02862
02863 static void setupTexenvAmbient(Color ambientColor)
02864 {
02865 float texenvConst[4];
02866 texenvConst[0] = ambientColor.red();
02867 texenvConst[1] = ambientColor.green();
02868 texenvConst[2] = ambientColor.blue();
02869 texenvConst[3] = ambientColor.alpha();
02870
02871 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02872
02873
02874
02875
02876 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
02877 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, texenvConst);
02878 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02879 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
02880 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
02881 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02882 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
02883 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
02884 glEnable(GL_TEXTURE_2D);
02885 }
02886
02887
02888 static void setupTexenvGlossMapAlpha()
02889 {
02890 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
02891 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
02892 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
02893 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
02894 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
02895 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_ALPHA);
02896
02897 }
02898
02899
02900 static void
02901 setEclipseShadowShaderConstants(const LightingState& ls,
02902 float planetRadius,
02903 const Mat4f& planetMat,
02904 CelestiaGLProgram& prog)
02905 {
02906 for (unsigned int li = 0;
02907 li < min(ls.nLights, MaxShaderLights);
02908 li++)
02909 {
02910 vector<EclipseShadow>* shadows = ls.shadows[li];
02911
02912 if (shadows != NULL)
02913 {
02914 unsigned int nShadows = min((size_t) MaxShaderShadows,
02915 shadows->size());
02916
02917 for (unsigned int i = 0; i < nShadows; i++)
02918 {
02919 EclipseShadow& shadow = shadows->at(i);
02920 CelestiaGLProgramShadow& shadowParams = prog.shadows[li][i];
02921
02922 float R2 = 0.25f;
02923 float umbra = shadow.umbraRadius / shadow.penumbraRadius;
02924 umbra = umbra * umbra;
02925 if (umbra < 0.0001f)
02926 umbra = 0.0001f;
02927 else if (umbra > 0.99f)
02928 umbra = 0.99f;
02929
02930 float umbraRadius = R2 * umbra;
02931 float penumbraRadius = R2;
02932 float shadowBias = 1.0f / (1.0f - penumbraRadius / umbraRadius);
02933 shadowParams.bias = shadowBias;
02934 shadowParams.scale = -shadowBias / umbraRadius;
02935
02936
02937
02938 Point3f origin = shadow.origin * planetMat;
02939 Vec3f dir = shadow.direction * planetMat;
02940 float scale = planetRadius / shadow.penumbraRadius;
02941 Vec3f axis = Vec3f(0, 1, 0) ^ dir;
02942 float angle = (float) acos(Vec3f(0, 1, 0) * dir);
02943 axis.normalize();
02944 Mat4f mat = Mat4f::rotation(axis, -angle);
02945 Vec3f sAxis = Vec3f(0.5f * scale, 0, 0) * mat;
02946 Vec3f tAxis = Vec3f(0, 0, 0.5f * scale) * mat;
02947
02948 float sw = (Point3f(0, 0, 0) - origin) * sAxis / planetRadius + 0.5f;
02949 float tw = (Point3f(0, 0, 0) - origin) * tAxis / planetRadius + 0.5f;
02950 shadowParams.texGenS = Vec4f(sAxis.x, sAxis.y, sAxis.z, sw);
02951 shadowParams.texGenT = Vec4f(tAxis.x, tAxis.y, tAxis.z, tw);
02952 }
02953 }
02954 }
02955 }
02956
02957
02958 static void setLightParameters_VP(VertexProcessor& vproc,
02959 const LightingState& ls,
02960 Color materialDiffuse,
02961 Color materialSpecular)
02962 {
02963 Vec3f diffuseColor(materialDiffuse.red(),
02964 materialDiffuse.green(),
02965 materialDiffuse.blue());
02966 Vec3f specularColor(materialSpecular.red(),
02967 materialSpecular.green(),
02968 materialSpecular.blue());
02969
02970 for (unsigned int i = 0; i < ls.nLights; i++)
02971 {
02972 const DirectionalLight& light = ls.lights[i];
02973
02974 Vec3f lightColor = Vec3f(light.color.red(),
02975 light.color.green(),
02976 light.color.blue()) * light.irradiance;
02977 Vec3f diffuse(diffuseColor.x * lightColor.x,
02978 diffuseColor.y * lightColor.y,
02979 diffuseColor.z * lightColor.z);
02980 Vec3f specular(specularColor.x * lightColor.x,
02981 specularColor.y * lightColor.y,
02982 specularColor.z * lightColor.z);
02983
02984
02985 if (i == 0)
02986 {
02987 vproc.parameter(vp::LightDirection0, ls.lights[0].direction_obj);
02988 vproc.parameter(vp::DiffuseColor0, diffuse);
02989 vproc.parameter(vp::SpecularColor0, specular);
02990 }
02991 else if (i == 1)
02992 {
02993 vproc.parameter(vp::LightDirection1, ls.lights[1].direction_obj);
02994 vproc.parameter(vp::DiffuseColor1, diffuse);
02995 vproc.parameter(vp::SpecularColor1, specular);
02996 }
02997 }
02998 }
02999
03000
03001 static void setLightParameters_GLSL(CelestiaGLProgram& prog,
03002 const ShaderProperties& shadprop,
03003 const LightingState& ls,
03004 Color materialDiffuse,
03005 Color materialSpecular)
03006 {
03007 unsigned int nLights = min(MaxShaderLights, ls.nLights);
03008
03009 Vec3f diffuseColor(materialDiffuse.red(),
03010 materialDiffuse.green(),
03011 materialDiffuse.blue());
03012 Vec3f specularColor(materialSpecular.red(),
03013 materialSpecular.green(),
03014 materialSpecular.blue());
03015
03016 for (unsigned int i = 0; i < nLights; i++)
03017 {
03018 const DirectionalLight& light = ls.lights[i];
03019
03020 Vec3f lightColor = Vec3f(light.color.red(),
03021 light.color.green(),
03022 light.color.blue()) * light.irradiance;
03023 prog.lights[i].direction = light.direction_obj;
03024
03025 if (shadprop.usesShadows() ||
03026 shadprop.usesFragmentLighting() ||
03027 shadprop.lightModel == ShaderProperties::RingIllumModel)
03028 {
03029 prog.fragLightColor[i] = Vec3f(lightColor.x * diffuseColor.x,
03030 lightColor.y * diffuseColor.y,
03031 lightColor.z * diffuseColor.z);
03032 if (shadprop.lightModel == ShaderProperties::SpecularModel)
03033 {
03034 prog.fragLightSpecColor[i] = Vec3f(lightColor.x * specularColor.x,
03035 lightColor.y * specularColor.y,
03036 lightColor.z * specularColor.z);
03037 }
03038 }
03039 else
03040 {
03041 prog.lights[i].diffuse = Vec3f(lightColor.x * diffuseColor.x,
03042 lightColor.y * diffuseColor.y,
03043 lightColor.z * diffuseColor.z);
03044 }
03045 prog.lights[i].specular = Vec3f(lightColor.x * specularColor.x,
03046 lightColor.y * specularColor.y,
03047 lightColor.z * specularColor.z);
03048
03049 Vec3f halfAngle_obj = ls.eyeDir_obj + light.direction_obj;
03050 if (halfAngle_obj.length() != 0.0f)
03051 halfAngle_obj.normalize();
03052 prog.lights[i].halfVector = halfAngle_obj;
03053 }
03054 }
03055
03056
03057 static void renderModelDefault(Model* model,
03058 const RenderInfo& ri,
03059 bool lit)
03060 {
03061 FixedFunctionRenderContext rc;
03062
03063
03064 if (lit)
03065 glEnable(GL_LIGHTING);
03066 else
03067 glDisable(GL_LIGHTING);
03068
03069 if (ri.baseTex == NULL)
03070 {
03071 glDisable(GL_TEXTURE_2D);
03072 }
03073 else
03074 {
03075 glEnable(GL_TEXTURE_2D);
03076 ri.baseTex->bind();
03077 }
03078
03079 glColor(ri.color);
03080
03081 if (ri.baseTex != NULL)
03082 rc.lock();
03083
03084 model->render(rc);
03085 if (model->usesTextureType(Mesh::EmissiveMap))
03086 {
03087 glDisable(GL_LIGHTING);
03088 glEnable(GL_BLEND);
03089 glBlendFunc(GL_ONE, GL_ONE);
03090 rc.setRenderPass(RenderContext::EmissivePass);
03091 rc.setMaterial(NULL);
03092
03093 model->render(rc);
03094 }
03095
03096
03097 float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
03098 float zero = 0.0f;
03099 glColor4fv(black);
03100 glMaterialfv(GL_FRONT, GL_EMISSION, black);
03101 glMaterialfv(GL_FRONT, GL_SPECULAR, black);
03102 glMaterialfv(GL_FRONT, GL_SHININESS, &zero);
03103 }
03104
03105
03106 static void renderModel_GLSL(Model* Model,
03107 const LightingState& ls,
03108 float radius,
03109 const Mat4f& planetMat)
03110 {
03111 glDisable(GL_LIGHTING);
03112 }
03113
03114
03115 static void renderSphereDefault(const RenderInfo& ri,
03116 const Frustum& frustum,
03117 bool lit,
03118 const GLContext& context)
03119 {
03120 if (lit)
03121 glEnable(GL_LIGHTING);
03122 else
03123 glDisable(GL_LIGHTING);
03124
03125 if (ri.baseTex == NULL)
03126 {
03127 glDisable(GL_TEXTURE_2D);
03128 }
03129 else
03130 {
03131 glEnable(GL_TEXTURE_2D);
03132 ri.baseTex->bind();
03133 }
03134
03135 glColor(ri.color);
03136
03137 lodSphere->render(context,
03138 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03139 frustum, ri.pixWidth,
03140 ri.baseTex);
03141 if (ri.nightTex != NULL && ri.useTexEnvCombine)
03142 {
03143 ri.nightTex->bind();
03144 setupNightTextureCombine();
03145 glEnable(GL_BLEND);
03146 glBlendFunc(GL_ONE, GL_ONE);
03147 glAmbientLightColor(Color::Black);
03148 lodSphere->render(context,
03149 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03150 frustum, ri.pixWidth,
03151 ri.nightTex);
03152 glAmbientLightColor(ri.ambientColor);
03153 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03154 }
03155
03156 if (ri.overlayTex != NULL)
03157 {
03158 ri.overlayTex->bind();
03159 glEnable(GL_BLEND);
03160 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
03161 lodSphere->render(context,
03162 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03163 frustum, ri.pixWidth,
03164 ri.overlayTex);
03165 glBlendFunc(GL_ONE, GL_ONE);
03166 }
03167 }
03168
03169
03170
03171
03172 static void renderSphere_Combiners(const RenderInfo& ri,
03173 const Frustum& frustum,
03174 const GLContext& context)
03175 {
03176 glDisable(GL_LIGHTING);
03177
03178 if (ri.baseTex == NULL)
03179 {
03180 glDisable(GL_TEXTURE_2D);
03181 }
03182 else
03183 {
03184 glEnable(GL_TEXTURE_2D);
03185 ri.baseTex->bind();
03186 }
03187
03188 glColor(ri.color * ri.sunColor);
03189
03190 if (ri.bumpTex != NULL)
03191 {
03192 renderBumpMappedMesh(context,
03193 *(ri.baseTex),
03194 *(ri.bumpTex),
03195 ri.sunDir_eye,
03196 ri.orientation,
03197 ri.ambientColor,
03198 frustum,
03199 ri.pixWidth);
03200 }
03201 else if (ri.baseTex != NULL)
03202 {
03203 renderSmoothMesh(context,
03204 *(ri.baseTex),
03205 ri.sunDir_eye,
03206 ri.orientation,
03207 ri.ambientColor,
03208 ri.pixWidth,
03209 frustum);
03210 }
03211 else
03212 {
03213 glEnable(GL_LIGHTING);
03214 lodSphere->render(context, frustum, ri.pixWidth, NULL, 0);
03215 }
03216
03217 if (ri.nightTex != NULL)
03218 {
03219 ri.nightTex->bind();
03220 glEnable(GL_BLEND);
03221 glBlendFunc(GL_ONE, GL_ONE);
03222 renderSmoothMesh(context,
03223 *(ri.nightTex),
03224 ri.sunDir_eye,
03225 ri.orientation,
03226 Color::Black,
03227 ri.pixWidth,
03228 frustum,
03229 true);
03230 }
03231
03232 if (ri.overlayTex != NULL)
03233 {
03234 glEnable(GL_LIGHTING);
03235 ri.overlayTex->bind();
03236 glEnable(GL_BLEND);
03237 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
03238 lodSphere->render(context,
03239 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03240 frustum, ri.pixWidth,
03241 ri.overlayTex);
03242 #if 0
03243 renderSmoothMesh(context,
03244 *(ri.overlayTex),
03245 ri.sunDir_eye,
03246 ri.orientation,
03247 ri.ambientColor,
03248 ri.pixWidth,
03249 frustum);
03250 #endif
03251 glBlendFunc(GL_ONE, GL_ONE);
03252 }
03253
03254 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
03255 }
03256
03257
03258 static void renderSphere_DOT3_VP(const RenderInfo& ri,
03259 const LightingState& ls,
03260 const Frustum& frustum,
03261 const GLContext& context)
03262 {
03263 VertexProcessor* vproc = context.getVertexProcessor();
03264 assert(vproc != NULL);
03265
03266 if (ri.baseTex == NULL)
03267 {
03268 glDisable(GL_TEXTURE_2D);
03269 }
03270 else
03271 {
03272 glEnable(GL_TEXTURE_2D);
03273 ri.baseTex->bind();
03274 }
03275
03276 vproc->enable();
03277 vproc->parameter(vp::EyePosition, ri.eyePos_obj);
03278 setLightParameters_VP(*vproc, ls, ri.color, ri.specularColor);
03279
03280 vproc->parameter(vp::AmbientColor, ri.ambientColor * ri.color);
03281 vproc->parameter(vp::SpecularExponent, 0.0f, 1.0f, 0.5f, ri.specularPower);
03282
03283 if (ri.bumpTex != NULL && ri.baseTex != NULL)
03284 {
03285
03286
03287 vproc->use(vp::diffuseBump);
03288 if (ri.ambientColor != Color::Black)
03289 {
03290
03291
03292
03293
03294
03295
03296
03297 setupTexenvAmbient(ri.ambientColor);
03298 lodSphere->render(context,
03299 LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
03300 frustum, ri.pixWidth,
03301 ri.baseTex);
03302
03303
03304 glEnable(GL_BLEND);
03305 glBlendFunc(GL_ONE, GL_ONE);
03306 setupBumpTexenv();
03307 lodSphere->render(context,
03308 LODSphereMesh::Normals | LODSphereMesh::Tangents |
03309 LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
03310 frustum, ri.pixWidth,
03311 ri.bumpTex, ri.baseTex);
03312 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03313 glDisable(GL_BLEND);
03314 }
03315 else
03316 {
03317 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
03318 ri.baseTex->bind();
03319 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
03320 ri.bumpTex->bind();
03321 setupBumpTexenv();
03322 lodSphere->render(context,
03323 LODSphereMesh::Normals | LODSphereMesh::Tangents |
03324 LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
03325 frustum, ri.pixWidth,
03326 ri.bumpTex, ri.baseTex);
03327 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03328 }
03329 }
03330 else
03331 {
03332 if (ls.nLights > 1)
03333 vproc->use(vp::diffuse_2light);
03334 else
03335 vproc->use(vp::diffuse);
03336 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03337 lodSphere->render(context,
03338 LODSphereMesh::Normals | LODSphereMesh::TexCoords0 |
03339 LODSphereMesh::VertexProgParams,
03340 frustum, ri.pixWidth,
03341 ri.baseTex);
03342 }
03343
03344
03345
03346 if (ri.specularColor != Color::Black)
03347 {
03348 glEnable(GL_BLEND);
03349 glBlendFunc(GL_ONE, GL_ONE);
03350 vproc->use(vp::glossMap);
03351
03352 if (ri.glossTex != NULL)
03353 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03354 else
03355 setupTexenvGlossMapAlpha();
03356
03357 lodSphere->render(context,
03358 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03359 frustum, ri.pixWidth,
03360 ri.glossTex != NULL ? ri.glossTex : ri.baseTex);
03361
03362 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03363 glDisable(GL_BLEND);
03364 }
03365
03366 if (ri.nightTex != NULL)
03367 {
03368 ri.nightTex->bind();
03369 if (ls.nLights > 1)
03370 vproc->use(vp::nightLights_2light);
03371 else
03372 vproc->use(vp::nightLights);
03373 setupNightTextureCombine();
03374 glEnable(GL_BLEND);
03375 glBlendFunc(GL_ONE, GL_ONE);
03376 lodSphere->render(context,
03377 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03378 frustum, ri.pixWidth,
03379 ri.nightTex);
03380 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03381 }
03382
03383 if (ri.overlayTex != NULL)
03384 {
03385 ri.overlayTex->bind();
03386 vproc->use(vp::diffuse);
03387 glEnable(GL_BLEND);
03388 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
03389 lodSphere->render(context,
03390 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03391 frustum, ri.pixWidth,
03392 ri.overlayTex);
03393 glBlendFunc(GL_ONE, GL_ONE);
03394 }
03395
03396 vproc->disable();
03397 }
03398
03399
03400 static void renderSphere_Combiners_VP(const RenderInfo& ri,
03401 const LightingState& ls,
03402 const Frustum& frustum,
03403 const GLContext& context)
03404 {
03405 Texture* textures[4];
03406 VertexProcessor* vproc = context.getVertexProcessor();
03407 assert(vproc != NULL);
03408
03409 if (ri.baseTex == NULL)
03410 {
03411 glDisable(GL_TEXTURE_2D);
03412 }
03413 else
03414 {
03415 glEnable(GL_TEXTURE_2D);
03416 ri.baseTex->bind();
03417 }
03418
03419
03420 float hazeDensity = ri.hazeColor.alpha();
03421
03422 if (hazeDensity > 0.0f && !buggyVertexProgramEmulation)
03423 {
03424 glEnable(GL_FOG);
03425 float fogColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
03426 fogColor[0] = ri.hazeColor.red();
03427 fogColor[1] = ri.hazeColor.green();
03428 fogColor[2] = ri.hazeColor.blue();
03429 glFogfv(GL_FOG_COLOR, fogColor);
03430 glFogi(GL_FOG_MODE, GL_LINEAR);
03431 glFogf(GL_FOG_START, 0.0);
03432 glFogf(GL_FOG_END, 1.0f / hazeDensity);
03433 }
03434
03435 vproc->enable();
03436
03437 vproc->parameter(vp::EyePosition, ri.eyePos_obj);
03438 setLightParameters_VP(*vproc, ls, ri.color, ri.specularColor);
03439
03440 vproc->parameter(vp::SpecularExponent, 0.0f, 1.0f, 0.5f, ri.specularPower);
03441 vproc->parameter(vp::AmbientColor, ri.ambientColor * ri.color);
03442 vproc->parameter(vp::HazeColor, ri.hazeColor);
03443
03444 if (ri.bumpTex != NULL)
03445 {
03446 if (hazeDensity > 0.0f)
03447 vproc->use(vp::diffuseBumpHaze);
03448 else
03449 vproc->use(vp::diffuseBump);
03450 SetupCombinersDecalAndBumpMap(*(ri.bumpTex),
03451 ri.ambientColor * ri.color,
03452 ri.sunColor * ri.color);
03453 lodSphere->render(context,
03454 LODSphereMesh::Normals | LODSphereMesh::Tangents |
03455 LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
03456 frustum, ri.pixWidth,
03457 ri.baseTex, ri.bumpTex);
03458 DisableCombiners();
03459
03460
03461 if (ri.specularColor != Color::Black)
03462 {
03463 glEnable(GL_BLEND);
03464 glBlendFunc(GL_ONE, GL_ONE);
03465 glEnable(GL_COLOR_SUM_EXT);
03466 vproc->use(vp::specular);
03467
03468
03469 vproc->parameter(vp::AmbientColor, Color::Black);
03470 vproc->parameter(vp::DiffuseColor0, Color::Black);
03471 SetupCombinersGlossMap(ri.glossTex != NULL ? GL_TEXTURE0_ARB : 0);
03472
03473 textures[0] = ri.glossTex != NULL ? ri.glossTex : ri.baseTex;
03474 lodSphere->render(context,
03475 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03476 frustum, ri.pixWidth,
03477 textures, 1);
03478
03479
03480 vproc->parameter(vp::DiffuseColor0, ri.sunColor * ri.color);
03481
03482 DisableCombiners();
03483 glDisable(GL_COLOR_SUM_EXT);
03484 glDisable(GL_BLEND);
03485 }
03486 }
03487 else if (ri.specularColor != Color::Black)
03488 {
03489 glEnable(GL_COLOR_SUM_EXT);
03490 if (ls.nLights > 1)
03491 vproc->use(vp::specular_2light);
03492 else
03493 vproc->use(vp::specular);
03494 SetupCombinersGlossMapWithFog(ri.glossTex != NULL ? GL_TEXTURE1_ARB : 0);
03495 unsigned int attributes = LODSphereMesh::Normals | LODSphereMesh::TexCoords0 |
03496 LODSphereMesh::VertexProgParams;
03497 lodSphere->render(context,
03498 attributes, frustum, ri.pixWidth,
03499 ri.baseTex, ri.glossTex);
03500 DisableCombiners();
03501 glDisable(GL_COLOR_SUM_EXT);
03502 }
03503 else
03504 {
03505 if (ls.nLights > 1)
03506 {
03507 if (hazeDensity > 0.0f)
03508 vproc->use(vp::diffuseHaze_2light);
03509 else
03510 vproc->use(vp::diffuse_2light);
03511 }
03512 else
03513 {
03514 if (hazeDensity > 0.0f)
03515 vproc->use(vp::diffuseHaze);
03516 else
03517 vproc->use(vp::diffuse);
03518 }
03519
03520 lodSphere->render(context,
03521 LODSphereMesh::Normals | LODSphereMesh::TexCoords0 |
03522 LODSphereMesh::VertexProgParams,
03523 frustum, ri.pixWidth,
03524 ri.baseTex);
03525 }
03526
03527 if (hazeDensity > 0.0f)
03528 glDisable(GL_FOG);
03529
03530 if (ri.nightTex != NULL)
03531 {
03532 ri.nightTex->bind();
03533 if (ls.nLights > 1)
03534 vproc->use(vp::nightLights_2light);
03535 else
03536 vproc->use(vp::nightLights);
03537 setupNightTextureCombine();
03538 glEnable(GL_BLEND);
03539 glBlendFunc(GL_ONE, GL_ONE);
03540 lodSphere->render(context,
03541 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03542 frustum, ri.pixWidth,
03543 ri.nightTex);
03544 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03545 }
03546
03547 if (ri.overlayTex != NULL)
03548 {
03549 ri.overlayTex->bind();
03550 vproc->use(vp::diffuse);
03551 glEnable(GL_BLEND);
03552 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
03553 lodSphere->render(context,
03554 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03555 frustum, ri.pixWidth,
03556 ri.overlayTex);
03557 glBlendFunc(GL_ONE, GL_ONE);
03558 }
03559
03560 vproc->disable();
03561 }
03562
03563
03564
03565 static void renderSphere_FP_VP(const RenderInfo& ri,
03566 const Frustum& frustum,
03567 const GLContext& context)
03568 {
03569 Texture* textures[4];
03570 VertexProcessor* vproc = context.getVertexProcessor();
03571 FragmentProcessor* fproc = context.getFragmentProcessor();
03572 assert(vproc != NULL && fproc != NULL);
03573
03574 if (ri.baseTex == NULL)
03575 {
03576 glDisable(GL_TEXTURE_2D);
03577 }
03578 else
03579 {
03580 glEnable(GL_TEXTURE_2D);
03581 ri.baseTex->bind();
03582 }
03583
03584
03585 Vec3f halfAngle_obj = ri.eyeDir_obj + ri.sunDir_obj;
03586 if (halfAngle_obj.length() != 0.0f)
03587 halfAngle_obj.normalize();
03588
03589
03590 float hazeDensity = ri.hazeColor.alpha();
03591
03592 if (hazeDensity > 0.0f)
03593 {
03594 glEnable(GL_FOG);
03595 float fogColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
03596 fogColor[0] = ri.hazeColor.red();
03597 fogColor[1] = ri.hazeColor.green();
03598 fogColor[2] = ri.hazeColor.blue();
03599 glFogfv(GL_FOG_COLOR, fogColor);
03600 glFogi(GL_FOG_MODE, GL_LINEAR);
03601 glFogf(GL_FOG_START, 0.0);
03602 glFogf(GL_FOG_END, 1.0f / hazeDensity);
03603 }
03604
03605 vproc->enable();
03606
03607 vproc->parameter(vp::EyePosition, ri.eyePos_obj);
03608 vproc->parameter(vp::LightDirection0, ri.sunDir_obj);
03609 vproc->parameter(vp::DiffuseColor0, ri.sunColor * ri.color);
03610 vproc->parameter(vp::SpecularExponent, 0.0f, 1.0f, 0.5f, ri.specularPower);
03611 vproc->parameter(vp::SpecularColor0, ri.sunColor * ri.specularColor);
03612 vproc->parameter(vp::AmbientColor, ri.ambientColor * ri.color);
03613 vproc->parameter(vp::HazeColor, ri.hazeColor);
03614
03615 if (ri.bumpTex != NULL)
03616 {
03617 fproc->enable();
03618
03619 if (hazeDensity > 0.0f)
03620 vproc->use(vp::diffuseBumpHaze);
03621 else
03622 vproc->use(vp::diffuseBump);
03623 fproc->use(fp::texDiffuseBump);
03624 lodSphere->render(context,
03625 LODSphereMesh::Normals | LODSphereMesh::Tangents |
03626 LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
03627 frustum, ri.pixWidth,
03628 ri.baseTex, ri.bumpTex);
03629 fproc->disable();
03630
03631
03632 if (ri.specularColor != Color::Black)
03633 {
03634 glEnable(GL_BLEND);
03635 glBlendFunc(GL_ONE, GL_ONE);
03636 glEnable(GL_COLOR_SUM_EXT);
03637 vproc->use(vp::specular);
03638
03639
03640 vproc->parameter(vp::AmbientColor, Color::Black);
03641 vproc->parameter(vp::DiffuseColor0, Color::Black);
03642 SetupCombinersGlossMap(ri.glossTex != NULL ? GL_TEXTURE0_ARB : 0);
03643
03644 textures[0] = ri.glossTex != NULL ? ri.glossTex : ri.baseTex;
03645 lodSphere->render(context,
03646 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03647 frustum, ri.pixWidth,
03648 textures, 1);
03649
03650
03651 vproc->parameter(vp::DiffuseColor0, ri.sunColor * ri.color);
03652
03653 DisableCombiners();
03654 glDisable(GL_COLOR_SUM_EXT);
03655 glDisable(GL_BLEND);
03656 }
03657 }
03658 else if (ri.specularColor != Color::Black)
03659 {
03660 fproc->enable();
03661 if (ri.glossTex == NULL)
03662 {
03663 vproc->use(vp::perFragmentSpecularAlpha);
03664 fproc->use(fp::texSpecularAlpha);
03665 }
03666 else
03667 {
03668 vproc->use(vp::perFragmentSpecular);
03669 fproc->use(fp::texSpecular);
03670 }
03671 fproc->parameter(fp::DiffuseColor, ri.sunColor * ri.color);
03672 fproc->parameter(fp::SunDirection, ri.sunDir_obj);
03673 fproc->parameter(fp::SpecularColor, ri.specularColor);
03674 fproc->parameter(fp::SpecularExponent, ri.specularPower, 0.0f, 0.0f, 0.0f);
03675 fproc->parameter(fp::AmbientColor, ri.ambientColor);
03676
03677 unsigned int attributes = LODSphereMesh::Normals |
03678 LODSphereMesh::TexCoords0 |
03679 LODSphereMesh::VertexProgParams;
03680 lodSphere->render(context,
03681 attributes, frustum, ri.pixWidth,
03682 ri.baseTex, ri.glossTex);
03683 fproc->disable();
03684 }
03685 else
03686 {
03687 fproc->enable();
03688 if (hazeDensity > 0.0f)
03689 vproc->use(vp::diffuseHaze);
03690 else
03691 vproc->use(vp::diffuse);
03692 fproc->use(fp::texDiffuse);
03693 lodSphere->render(context,
03694 LODSphereMesh::Normals | LODSphereMesh::TexCoords0 |
03695 LODSphereMesh::VertexProgParams,
03696 frustum, ri.pixWidth,
03697 ri.baseTex);
03698 fproc->disable();
03699 }
03700
03701 if (hazeDensity > 0.0f)
03702 glDisable(GL_FOG);
03703
03704 if (ri.nightTex != NULL)
03705 {
03706 ri.nightTex->bind();
03707 vproc->use(vp::nightLights);
03708 setupNightTextureCombine();
03709 glEnable(GL_BLEND);
03710 glBlendFunc(GL_ONE, GL_ONE);
03711 lodSphere->render(context,
03712 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03713 frustum, ri.pixWidth,
03714 ri.nightTex);
03715 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
03716 }
03717
03718 if (ri.overlayTex != NULL)
03719 {
03720 ri.overlayTex->bind();
03721 vproc->use(vp::diffuse);
03722 glEnable(GL_BLEND);
03723 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
03724 lodSphere->render(context,
03725 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
03726 frustum, ri.pixWidth,
03727 ri.overlayTex);
03728 glBlendFunc(GL_ONE, GL_ONE);
03729 }
03730
03731 vproc->disable();
03732 }
03733
03734
03735 static void renderSphere_GLSL(const RenderInfo& ri,
03736 const LightingState& ls,
03737 RingSystem* rings,
03738 float radius,
03739 const Mat4f& planetMat,
03740 const Frustum& frustum,
03741 const GLContext& context)
03742 {
03743 Texture* textures[4] = { NULL, NULL, NULL, NULL };
03744 unsigned int nTextures = 0;
03745
03746
03747
03748
03749 glDisable(GL_LIGHTING);
03750
03751 ShaderProperties shadprop;
03752 shadprop.nLights = min(ls.nLights, MaxShaderLights);
03753
03754
03755 if (ri.baseTex != NULL)
03756 {
03757 shadprop.texUsage = ShaderProperties::DiffuseTexture;
03758 textures[nTextures++] = ri.baseTex;
03759 }
03760
03761 if (ri.bumpTex != NULL)
03762 {
03763 shadprop.texUsage |= ShaderProperties::NormalTexture;
03764 textures[nTextures++] = ri.bumpTex;
03765 }
03766
03767 if (ri.specularColor != Color::Black)
03768 {
03769 shadprop.lightModel = ShaderProperties::SpecularModel;
03770 if (ri.glossTex == NULL)
03771 {
03772 shadprop.texUsage |= ShaderProperties::SpecularInDiffuseAlpha;
03773 }
03774 else
03775 {
03776 shadprop.texUsage |= ShaderProperties::SpecularTexture;
03777 textures[nTextures++] = ri.glossTex;
03778 }
03779 }
03780
03781 if (ri.nightTex != NULL)
03782 {
03783 shadprop.texUsage |= ShaderProperties::NightTexture;
03784 textures[nTextures++] = ri.nightTex;
03785 }
03786
03787 if (rings != NULL)
03788 #if 0
03789 (renderFlags & ShowRingShadows) != 0)
03790 #endif
03791 {
03792 Texture* ringsTex = rings->texture.find(medres);
03793 if (ringsTex != NULL)
03794 {
03795 glx::glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
03796 ringsTex->bind();
03797 nTextures++;
03798
03799
03800
03801 float bc[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
03802 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bc);
03803 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
03804 GL_CLAMP_TO_BORDER_ARB);
03805 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
03806
03807 shadprop.texUsage |= ShaderProperties::RingShadowTexture;
03808 }
03809 }
03810
03811
03812
03813
03814 unsigned int totalShadows = 0;
03815 for (unsigned int li = 0; li < ls.nLights; li++)
03816 {
03817 if (ls.shadows[li] && !ls.shadows[li]->empty())
03818 {
03819 unsigned int nShadows = (unsigned int) min((size_t) MaxShaderShadows, ls.shadows[li]->size());
03820 shadprop.setShadowCountForLight(li, nShadows);
03821 totalShadows += nShadows;
03822 }
03823 }
03824
03825
03826 CelestiaGLProgram* prog = GetShaderManager().getShader(shadprop);
03827 if (prog == NULL)
03828 return;
03829
03830 prog->use();
03831
03832 setLightParameters_GLSL(*prog, shadprop, ls,
03833 ri.color, ri.specularColor);
03834
03835 prog->shininess = ri.specularPower;
03836 prog->ambientColor = Vec3f(ri.ambientColor.red(), ri.ambientColor.green(),
03837 ri.ambientColor.blue());
03838
03839 if (shadprop.texUsage & ShaderProperties::RingShadowTexture)
03840 {
03841 float ringWidth = rings->outerRadius - rings->innerRadius;
03842 prog->ringRadius = rings->innerRadius / radius;
03843 prog->ringWidth = 1.0f / (ringWidth / radius);
03844 }
03845
03846 if (shadprop.shadowCounts != 0)
03847 setEclipseShadowShaderConstants(ls, radius, planetMat, *prog);
03848
03849 glColor(ri.color);
03850
03851 unsigned int attributes = LODSphereMesh::Normals;
03852 if (ri.bumpTex != NULL)
03853 attributes |= LODSphereMesh::Tangents;
03854 lodSphere->render(context,
03855 attributes,
03856 frustum, ri.pixWidth,
03857 textures[0], textures[1], textures[2], textures[3]);
03858
03859 glx::glUseProgramObjectARB(0);
03860 }
03861
03862
03863 static void renderClouds_GLSL(const RenderInfo& ri,
03864 const LightingState& ls,
03865 Texture* cloudTex,
03866 float texOffset,
03867 RingSystem* rings,
03868 float radius,
03869 const Mat4f& planetMat,
03870 const Frustum& frustum,
03871 const GLContext& context)
03872 {
03873 unsigned int nTextures = 0;
03874
03875 glDisable(GL_LIGHTING);
03876
03877 ShaderProperties shadprop;
03878 shadprop.nLights = ls.nLights;
03879
03880
03881 if (cloudTex != NULL)
03882 {
03883 shadprop.texUsage = ShaderProperties::DiffuseTexture;
03884 nTextures++;
03885 }
03886
03887 if (rings != NULL)
03888
03889 {
03890 Texture* ringsTex = rings->texture.find(medres);
03891 if (ringsTex != NULL)
03892 {
03893 glx::glActiveTextureARB(GL_TEXTURE0_ARB + nTextures);
03894 ringsTex->bind();
03895 nTextures++;
03896
03897
03898
03899 float bc[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
03900 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bc);
03901 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
03902 GL_CLAMP_TO_BORDER_ARB);
03903 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
03904
03905 shadprop.texUsage |= ShaderProperties::RingShadowTexture;
03906 }
03907 }
03908
03909
03910
03911
03912 unsigned int totalShadows = 0;
03913 for (unsigned int li = 0; li < ls.nLights; li++)
03914 {
03915 if (ls.shadows[li] && !ls.shadows[li]->empty())
03916 {
03917 unsigned int nShadows = (unsigned int) min((size_t) MaxShaderShadows, ls.shadows[li]->size());
03918 shadprop.setShadowCountForLight(li, nShadows);
03919 totalShadows += nShadows;
03920 }
03921 }
03922
03923
03924 CelestiaGLProgram* prog = GetShaderManager().getShader(shadprop);
03925 if (prog == NULL)
03926 return;
03927
03928 prog->use();
03929
03930 setLightParameters_GLSL(*prog, shadprop, ls,
03931 ri.color, ri.specularColor);
03932
03933 prog->ambientColor = Vec3f(ri.ambientColor.red(), ri.ambientColor.green(),
03934 ri.ambientColor.blue());
03935 prog->textureOffset = texOffset;
03936
03937 if (shadprop.texUsage & ShaderProperties::RingShadowTexture)
03938 {
03939 float ringWidth = rings->outerRadius - rings->innerRadius;
03940 prog->ringRadius = rings->innerRadius / radius;
03941 prog->ringWidth = 1.0f / (ringWidth / radius);
03942 }
03943
03944 if (shadprop.shadowCounts != 0)
03945 setEclipseShadowShaderConstants(ls, radius, planetMat, *prog);
03946
03947 unsigned int attributes = LODSphereMesh::Normals;
03948 lodSphere->render(context,
03949 LODSphereMesh::Normals,
03950 frustum, ri.pixWidth,
03951 cloudTex);
03952
03953 prog->textureOffset = 0.0f;
03954
03955 glx::glUseProgramObjectARB(0);
03956 }
03957
03958
03959 static void texGenPlane(GLenum coord, GLenum mode, const Vec4f& plane)
03960 {
03961 float f[4];
03962 f[0] = plane.x; f[1] = plane.y; f[2] = plane.z; f[3] = plane.w;
03963 glTexGenfv(coord, mode, f);
03964 }
03965
03966 static void renderShadowedModelDefault(Model* model,
03967 const RenderInfo& ri,
03968 const Frustum& frustum,
03969 float *sPlane,
03970 float *tPlane,
03971 const Vec3f& lightDir,
03972 bool useShadowMask,
03973 const GLContext& context)
03974 {
03975 glEnable(GL_TEXTURE_GEN_S);
03976 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
03977 glTexGenfv(GL_S, GL_OBJECT_PLANE, sPlane);
03978
03979 glEnable(GL_TEXTURE_GEN_T);
03980 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
03981 glTexGenfv(GL_T, GL_OBJECT_PLANE, tPlane);
03982
03983 if (useShadowMask)
03984 {
03985 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
03986 glEnable(GL_TEXTURE_GEN_S);
03987 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
03988 texGenPlane(GL_S, GL_OBJECT_PLANE,
03989 Vec4f(lightDir.x, lightDir.y, lightDir.z, 0.5f));
03990 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
03991 }
03992
03993 glColor4f(1, 1, 1, 1);
03994 glDisable(GL_LIGHTING);
03995
03996 if (model == NULL)
03997 {
03998 lodSphere->render(context,
03999 LODSphereMesh::Normals | LODSphereMesh::Multipass,
04000 frustum, ri.pixWidth, NULL);
04001 }
04002 else
04003 {
04004 FixedFunctionRenderContext rc;
04005 model->render(rc);
04006 }
04007 glEnable(GL_LIGHTING);
04008
04009 if (useShadowMask)
04010 {
04011 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
04012 glDisable(GL_TEXTURE_GEN_S);
04013 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
04014 }
04015 glDisable(GL_TEXTURE_GEN_S);
04016 glDisable(GL_TEXTURE_GEN_T);
04017 }
04018
04019
04020 static void renderShadowedModelVertexShader(const RenderInfo& ri,
04021 const Frustum& frustum,
04022 float* sPlane, float* tPlane,
04023 Vec3f& lightDir,
04024 const GLContext& context)
04025 {
04026 VertexProcessor* vproc = context.getVertexProcessor();
04027 assert(vproc != NULL);
04028
04029 vproc->enable();
04030 vproc->parameter(vp::LightDirection0, lightDir);
04031 vproc->parameter(vp::TexGen_S, sPlane);
04032 vproc->parameter(vp::TexGen_T, tPlane);
04033 vproc->use(vp::shadowTexture);
04034
04035 lodSphere->render(context,
04036 LODSphereMesh::Normals | LODSphereMesh::Multipass, frustum,
04037 ri.pixWidth, NULL);
04038
04039 vproc->disable();
04040 }
04041
04042
04043 static void renderRings(RingSystem& rings,
04044 RenderInfo& ri,
04045 float planetRadius,
04046 float planetOblateness,
04047 unsigned int textureResolution,
04048 bool renderShadow,
04049 const GLContext& context,
04050 unsigned int nSections)
04051 {
04052 float inner = rings.innerRadius / planetRadius;
04053 float outer = rings.outerRadius / planetRadius;
04054
04055
04056
04057
04058
04059
04060
04061
04062
04063
04064
04065
04066
04067 float ringIllumination = 0.0f;
04068 {
04069 float illumFraction = (1.0f + ri.eyeDir_obj * ri.sunDir_obj) / 2.0f;
04070
04071 ringIllumination = illumFraction;
04072 }
04073
04074 GLContext::VertexPath vpath = context.getVertexPath();
04075 VertexProcessor* vproc = context.getVertexProcessor();
04076 FragmentProcessor* fproc = context.getFragmentProcessor();
04077
04078 if (vproc != NULL)
04079 {
04080 vproc->enable();
04081 vproc->use(vp::ringIllum);
04082 vproc->parameter(vp::LightDirection0, ri.sunDir_obj);
04083 vproc->parameter(vp::DiffuseColor0, ri.sunColor * rings.color);
04084 vproc->parameter(vp::AmbientColor, ri.ambientColor * ri.color);
04085 vproc->parameter(vp::Constant0, Vec3f(0, 0.5, 1.0));
04086 }
04087
04088
04089
04090
04091
04092
04093 if (renderShadow)
04094 {
04095 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
04096 glEnable(GL_TEXTURE_2D);
04097 shadowTex->bind();
04098
04099 float sPlane[4] = { 0, 0, 0, 0.5f };
04100 float tPlane[4] = { 0, 0, 0, 0.5f };
04101
04102
04103
04104
04105
04106
04107
04108 Vec3f axis = Vec3f(0, 1, 0) ^ ri.sunDir_obj;
04109 float cosAngle = Vec3f(0.0f, 1.0f, 0.0f) * ri.sunDir_obj;
04110 float angle = (float) acos(cosAngle);
04111 axis.normalize();
04112
04113 float sScale = 1.0f;
04114 float tScale = 1.0f;
04115 if (fproc == NULL)
04116 {
04117
04118
04119
04120 sScale *= ShadowTextureScale;
04121 tScale *= ShadowTextureScale;
04122 }
04123
04124 if (planetOblateness != 0.0f)
04125 {
04126
04127
04128
04129
04130 float a = 1.0f;
04131 float b = a * (1.0f - planetOblateness);
04132 float ecc2 = 1.0f - (b * b) / (a * a);
04133
04134
04135
04136 float r = a * (float) sqrt((1.0f - ecc2) /
04137 (1.0f - ecc2 * square(cosAngle)));
04138
04139 tScale *= a / r;
04140 }
04141
04142
04143
04144 Vec3f sAxis = axis * 0.5f;
04145 Vec3f tAxis = (axis ^ ri.sunDir_obj) * 0.5f * tScale;
04146
04147 sPlane[0] = sAxis.x; sPlane[1] = sAxis.y; sPlane[2] = sAxis.z;
04148 tPlane[0] = tAxis.x; tPlane[1] = tAxis.y; tPlane[2] = tAxis.z;
04149
04150 if (vproc != NULL)
04151 {
04152 vproc->parameter(vp::TexGen_S, sPlane);
04153 vproc->parameter(vp::TexGen_T, tPlane);
04154 }
04155 else
04156 {
04157 glEnable(GL_TEXTURE_GEN_S);
04158 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
04159 glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
04160 glEnable(GL_TEXTURE_GEN_T);
04161 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
04162 glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
04163 }
04164
04165 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
04166
04167 if (fproc != NULL)
04168 {
04169 float r0 = 0.24f;
04170 float r1 = 0.25f;
04171 float bias = 1.0f / (1.0f - r1 / r0);
04172 float scale = -bias / r0;
04173
04174 fproc->enable();
04175 fproc->use(fp::sphereShadowOnRings);
04176 fproc->parameter(fp::ShadowParams0, scale, bias, 0.0f, 0.0f);
04177 fproc->parameter(fp::AmbientColor, ri.ambientColor * ri.color);
04178 }
04179 }
04180
04181 glEnable(GL_BLEND);
04182 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04183
04184 Texture* ringsTex = rings.texture.find(textureResolution);
04185
04186 if (ringsTex != NULL)
04187 ringsTex->bind();
04188 else
04189 glDisable(GL_TEXTURE_2D);
04190
04191
04192
04193
04194 if (vpath == GLContext::VPath_Basic)
04195 {
04196 glDisable(GL_LIGHTING);
04197 Vec3f litColor(rings.color.red(), rings.color.green(), rings.color.blue());
04198 litColor = litColor * ringIllumination +
04199 Vec3f(ri.ambientColor.red(), ri.ambientColor.green(),
04200 ri.ambientColor.blue());
04201 glColor4f(litColor.x, litColor.y, litColor.z, 1.0f);
04202 }
04203
04204
04205
04206
04207
04208
04209
04210
04211
04212
04213
04214 float sunAngle = (float) atan2(ri.sunDir_obj.z, ri.sunDir_obj.x);
04215
04216
04217
04218 if (vproc != NULL && fproc != NULL)
04219 glAmbientLightColor(Color::Black);
04220
04221 renderRingSystem(inner, outer,
04222 (float) (sunAngle + PI / 2),
04223 (float) (sunAngle + 3 * PI / 2),
04224 nSections / 2);
04225 renderRingSystem(inner, outer,
04226 (float) (sunAngle + 3 * PI / 2),
04227 (float) (sunAngle + PI / 2),
04228 nSections / 2);
04229
04230 if (vproc != NULL && fproc != NULL)
04231 glAmbientLightColor(ri.ambientColor * ri.color);
04232
04233
04234 if (renderShadow)
04235 {
04236 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
04237 glDisable(GL_TEXTURE_2D);
04238 glDisable(GL_TEXTURE_GEN_S);
04239 glDisable(GL_TEXTURE_GEN_T);
04240 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
04241
04242 if (fproc != NULL)
04243 fproc->disable();
04244 }
04245
04246
04247 renderRingSystem(inner, outer,
04248 (float) (sunAngle - PI / 2),
04249 (float) (sunAngle + PI / 2),
04250 nSections / 2);
04251 renderRingSystem(inner, outer,
04252 (float) (sunAngle + PI / 2),
04253 (float) (sunAngle - PI / 2),
04254 nSections / 2);
04255 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
04256
04257 if (vproc != NULL)
04258 vproc->disable();
04259 }
04260
04261
04262 static void renderRings_GLSL(RingSystem& rings,
04263 RenderInfo& ri,
04264 const LightingState& ls,
04265 float planetRadius,
04266 float planetOblateness,
04267 unsigned int textureResolution,
04268 bool renderShadow,
04269 unsigned int nSections)
04270 {
04271 float inner = rings.innerRadius / planetRadius;
04272 float outer = rings.outerRadius / planetRadius;
04273 Texture* ringsTex = rings.texture.find(textureResolution);
04274
04275 ShaderProperties shadprop;
04276
04277 {
04278 shadprop.lightModel = ShaderProperties::RingIllumModel;
04279 shadprop.nLights = min(ls.nLights, MaxShaderLights);
04280
04281 if (renderShadow)
04282 {
04283
04284 for (unsigned int li = 0; li < ls.nLights; li++)
04285 shadprop.setShadowCountForLight(li, 1);
04286 }
04287
04288 if (ringsTex)
04289 shadprop.texUsage = ShaderProperties::DiffuseTexture;
04290 }
04291
04292
04293
04294 CelestiaGLProgram* prog = GetShaderManager().getShader(shadprop);
04295 if (prog == NULL)
04296 return;
04297
04298 prog->use();
04299
04300 prog->eyePosition = ls.eyePos_obj;
04301 prog->ambientColor = Vec3f(ri.ambientColor.red(), ri.ambientColor.green(),
04302 ri.ambientColor.blue());
04303 setLightParameters_GLSL(*prog, shadprop, ls,
04304 ri.color, ri.specularColor);
04305
04306 for (unsigned int li = 0; li < ls.nLights; li++)
04307 {
04308 const DirectionalLight& light = ls.lights[li];
04309
04310
04311
04312
04313
04314
04315
04316 Vec3f axis = Vec3f(0, 1, 0) ^ light.direction_obj;
04317 float cosAngle = Vec3f(0.0f, 1.0f, 0.0f) * light.direction_obj;
04318 float angle = (float) acos(cosAngle);
04319 axis.normalize();
04320
04321 float tScale = 1.0f;
04322 if (planetOblateness != 0.0f)
04323 {
04324
04325
04326
04327
04328 float a = 1.0f;
04329 float b = a * (1.0f - planetOblateness);
04330 float ecc2 = 1.0f - (b * b) / (a * a);
04331
04332
04333
04334 float r = a * (float) sqrt((1.0f - ecc2) /
04335 (1.0f - ecc2 * square(cosAngle)));
04336
04337 tScale *= a / r;
04338 }
04339
04340
04341
04342 Vec3f sAxis = axis * 0.5f;
04343 Vec3f tAxis = (axis ^ light.direction_obj) * 0.5f * tScale;
04344 Vec4f texGenS(sAxis.x, sAxis.y, sAxis.z, 0.5f);
04345 Vec4f texGenT(tAxis.x, tAxis.y, tAxis.z, 0.5f);
04346
04347 float r0 = 0.24f;
04348 float r1 = 0.25f;
04349 float bias = 1.0f / (1.0f - r1 / r0);
04350 float scale = -bias / r0;
04351
04352 prog->shadows[li][0].texGenS = texGenS;
04353 prog->shadows[li][0].texGenT = texGenT;
04354 prog->shadows[li][0].bias = bias;
04355 prog->shadows[li][0].scale = -bias / r0;
04356 }
04357
04358 glEnable(GL_BLEND);
04359 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04360
04361 if (ringsTex != NULL)
04362 ringsTex->bind();
04363 else
04364 glDisable(GL_TEXTURE_2D);
04365
04366 renderRingSystem(inner, outer, 0, (float) PI * 2.0f, nSections);
04367 renderRingSystem(inner, outer, (float) PI * 2.0f, 0, nSections);
04368
04369 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
04370
04371 glx::glUseProgramObjectARB(0);
04372 }
04373
04374
04375 static void
04376 renderEclipseShadows(Model* model,
04377 vector<EclipseShadow>& eclipseShadows,
04378 RenderInfo& ri,
04379 float planetRadius,
04380 Mat4f& planetMat,
04381 Frustum& viewFrustum,
04382 const GLContext& context)
04383 {
04384
04385 if (model != NULL)
04386 return;
04387
04388 for (vector<EclipseShadow>::iterator iter = eclipseShadows.begin();
04389 iter != eclipseShadows.end(); iter++)
04390 {
04391 EclipseShadow shadow = *iter;
04392
04393 #ifdef DEBUG_ECLIPSE_SHADOWS
04394
04395
04396 glDisable(GL_TEXTURE_2D);
04397 glColor4f(1, 0, 0, 1);
04398 Point3f blorp = shadow.origin * planetMat;
04399 Vec3f blah = shadow.direction * planetMat;
04400 blorp.x /= planetRadius; blorp.y /= planetRadius; blorp.z /= planetRadius;
04401 float foo = blorp.distanceFromOrigin();
04402 glBegin(GL_LINES);
04403 glVertex(blorp);
04404 glVertex(blorp + foo * blah);
04405 glEnd();
04406 glEnable(GL_TEXTURE_2D);
04407 #endif
04408
04409
04410
04411
04412
04413
04414
04415
04416 Texture* eclipseTex = NULL;
04417 float umbra = shadow.umbraRadius / shadow.penumbraRadius;
04418 if (umbra < 0.1f)
04419 eclipseTex = eclipseShadowTextures[0];
04420 else if (umbra < 0.35f)
04421 eclipseTex = eclipseShadowTextures[1];
04422 else if (umbra < 0.6f)
04423 eclipseTex = eclipseShadowTextures[2];
04424 else if (umbra < 0.9f)
04425 eclipseTex = eclipseShadowTextures[3];
04426 else
04427 eclipseTex = shadowTex;
04428
04429
04430
04431 Point3f origin = shadow.origin * planetMat;
04432 Vec3f dir = shadow.direction * planetMat;
04433 float scale = planetRadius / shadow.penumbraRadius;
04434 Vec3f axis = Vec3f(0, 1, 0) ^ dir;
04435 float angle = (float) acos(Vec3f(0, 1, 0) * dir);
04436 axis.normalize();
04437 Mat4f mat = Mat4f::rotation(axis, -angle);
04438 Vec3f sAxis = Vec3f(0.5f * scale, 0, 0) * mat;
04439 Vec3f tAxis = Vec3f(0, 0, 0.5f * scale) * mat;
04440
04441 float sPlane[4] = { 0, 0, 0, 0 };
04442 float tPlane[4] = { 0, 0, 0, 0 };
04443 sPlane[0] = sAxis.x; sPlane[1] = sAxis.y; sPlane[2] = sAxis.z;
04444 tPlane[0] = tAxis.x; tPlane[1] = tAxis.y; tPlane[2] = tAxis.z;
04445 sPlane[3] = (Point3f(0, 0, 0) - origin) * sAxis / planetRadius + 0.5f;
04446 tPlane[3] = (Point3f(0, 0, 0) - origin) * tAxis / planetRadius + 0.5f;
04447
04448
04449
04450 if (eclipseTex != NULL)
04451 eclipseTex->bind();
04452
04453 glEnable(GL_BLEND);
04454 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
04455
04456
04457
04458 if (ri.useTexEnvCombine)
04459 {
04460 float color[4] = { ri.ambientColor.red(), ri.ambientColor.green(),
04461 ri.ambientColor.blue(), 1.0f };
04462 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
04463 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
04464 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_CONSTANT_EXT);
04465 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
04466 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
04467 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
04468 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
04469
04470
04471 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
04472 glEnable(GL_TEXTURE_2D);
04473 shadowMaskTexture->bind();
04474 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
04475 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
04476 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
04477 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
04478 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
04479 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
04480 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
04481 }
04482
04483
04484
04485
04486
04487 if (context.getVertexPath() != GLContext::VPath_Basic && model == NULL)
04488 {
04489 renderShadowedModelVertexShader(ri, viewFrustum,
04490 sPlane, tPlane,
04491 dir,
04492 context);
04493 }
04494 else
04495 {
04496 renderShadowedModelDefault(model, ri, viewFrustum,
04497 sPlane, tPlane,
04498 dir,
04499 ri.useTexEnvCombine,
04500 context);
04501 }
04502
04503 if (ri.useTexEnvCombine)
04504 {
04505
04506 glx::glActiveTextureARB(GL_TEXTURE1_ARB);
04507 glDisable(GL_TEXTURE_2D);
04508 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
04509 glx::glActiveTextureARB(GL_TEXTURE0_ARB);
04510
04511 float color[4] = { 0, 0, 0, 0 };
04512 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
04513 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
04514 }
04515
04516 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
04517 glDisable(GL_BLEND);
04518 }
04519 }
04520
04521
04522 static void
04523 renderEclipseShadows_Shaders(Model* model,
04524 vector<EclipseShadow>& eclipseShadows,
04525 RenderInfo& ri,
04526 float planetRadius,
04527 Mat4f& planetMat,
04528 Frustum& viewFrustum,
04529 const GLContext& context)
04530 {
04531
04532 if (model != NULL)
04533 return;
04534
04535 glEnable(GL_TEXTURE_2D);
04536 penumbraFunctionTexture->bind();
04537
04538 glEnable(GL_BLEND);
04539 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
04540
04541 float sPlanes[4][4];
04542 float tPlanes[4][4];
04543 float shadowParams[4][4];
04544
04545 int n = 0;
04546 for (vector<EclipseShadow>::iterator iter = eclipseShadows.begin();
04547 iter != eclipseShadows.end() && n < 4; iter++, n++)
04548 {
04549 EclipseShadow shadow = *iter;
04550
04551 float R2 = 0.25f;
04552 float umbra = shadow.umbraRadius / shadow.penumbraRadius;
04553 umbra = umbra * umbra;
04554 if (umbra < 0.0001f)
04555 umbra = 0.0001f;
04556 else if (umbra > 0.99f)
04557 umbra = 0.99f;
04558
04559 float umbraRadius = R2 * umbra;
04560 float penumbraRadius = R2;
04561 float shadowBias = 1.0f / (1.0f - penumbraRadius / umbraRadius);
04562 float shadowScale = -shadowBias / umbraRadius;
04563
04564 shadowParams[n][0] = shadowScale;
04565 shadowParams[n][1] = shadowBias;
04566 shadowParams[n][2] = 0.0f;
04567 shadowParams[n][3] = 0.0f;
04568
04569
04570
04571 Point3f origin = shadow.origin * planetMat;
04572 Vec3f dir = shadow.direction * planetMat;
04573 float scale = planetRadius / shadow.penumbraRadius;
04574 Vec3f axis = Vec3f(0, 1, 0) ^ dir;
04575 float angle = (float) acos(Vec3f(0, 1, 0) * dir);
04576 axis.normalize();
04577 Mat4f mat = Mat4f::rotation(axis, -angle);
04578 Vec3f sAxis = Vec3f(0.5f * scale, 0, 0) * mat;
04579 Vec3f tAxis = Vec3f(0, 0, 0.5f * scale) * mat;
04580
04581 sPlanes[n][0] = sAxis.x;
04582 sPlanes[n][1] = sAxis.y;
04583 sPlanes[n][2] = sAxis.z;
04584 sPlanes[n][3] = (Point3f(0, 0, 0) - origin) * sAxis / planetRadius + 0.5f;
04585 tPlanes[n][0] = tAxis.x;
04586 tPlanes[n][1] = tAxis.y;
04587 tPlanes[n][2] = tAxis.z;
04588 tPlanes[n][3] = (Point3f(0, 0, 0) - origin) * tAxis / planetRadius + 0.5f;
04589 }
04590
04591
04592 VertexProcessor* vproc = context.getVertexProcessor();
04593 FragmentProcessor* fproc = context.getFragmentProcessor();
04594
04595 vproc->enable();
04596 vproc->use(vp::multiShadow);
04597
04598 fproc->enable();
04599 if (n == 1)
04600 fproc->use(fp::eclipseShadow1);
04601 else
04602 fproc->use(fp::eclipseShadow2);
04603
04604 fproc->parameter(fp::ShadowParams0, shadowParams[0]);
04605 vproc->parameter(vp::TexGen_S, sPlanes[0]);
04606 vproc->parameter(vp::TexGen_T, tPlanes[0]);
04607 if (n >= 2)
04608 {
04609 fproc->parameter(fp::ShadowParams1, shadowParams[1]);
04610 vproc->parameter(vp::TexGen_S2, sPlanes[1]);
04611 vproc->parameter(vp::TexGen_T2, tPlanes[1]);
04612 }
04613 if (n >= 3)
04614 {
04615
04616 vproc->parameter(vp::TexGen_S3, sPlanes[2]);
04617 vproc->parameter(vp::TexGen_T3, tPlanes[2]);
04618 }
04619 if (n >= 4)
04620 {
04621
04622 vproc->parameter(vp::TexGen_S4, sPlanes[3]);
04623 vproc->parameter(vp::TexGen_T4, tPlanes[3]);
04624 }
04625
04626
04627
04628 lodSphere->render(context,
04629 LODSphereMesh::Normals | LODSphereMesh::Multipass,
04630 viewFrustum,
04631 ri.pixWidth, NULL);
04632
04633 vproc->disable();
04634 fproc->disable();
04635
04636 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
04637 glDisable(GL_BLEND);
04638 }
04639
04640
04641 static void
04642 renderRingShadowsVS(Model* model,
04643 const RingSystem& rings,
04644 const Vec3f& sunDir,
04645 RenderInfo& ri,
04646 float planetRadius,
04647 float oblateness,
04648 Mat4f& planetMat,
04649 Frustum& viewFrustum,
04650 const GLContext& context)
04651 {
04652
04653
04654 float ringWidth = rings.outerRadius - rings.innerRadius;
04655 float s = ri.sunDir_obj.y;
04656 float scale = (abs(s) < 0.001f) ? 1000.0f : 1.0f / s;
04657
04658 if (abs(s) > 1.0f - 1.0e-4f)
04659 {
04660
04661
04662
04663 return;
04664 }
04665
04666 glEnable(GL_BLEND);
04667 glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
04668
04669
04670
04671 float color[4] = { ri.ambientColor.red(), ri.ambientColor.green(),
04672 ri.ambientColor.blue(), 1.0f };
04673 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
04674 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
04675 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_CONSTANT_EXT);
04676 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
04677 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
04678 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
04679 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
04680
04681
04682
04683
04684
04685
04686 float bc[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
04687 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bc);
04688 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER_ARB);
04689
04690
04691
04692
04693
04694
04695
04696
04697
04698 float alpha = 1.0f;
04699
04700 VertexProcessor* vproc = context.getVertexProcessor();
04701 assert(vproc != NULL);
04702
04703 vproc->enable();
04704 vproc->use(vp::ringShadow);
04705 vproc->parameter(vp::LightDirection0, ri.sunDir_obj);
04706 vproc->parameter(vp::DiffuseColor0, 1, 1, 1, alpha);
04707 vproc->parameter(vp::TexGen_S,
04708 rings.innerRadius / planetRadius,
04709 1.0f / (ringWidth / planetRadius),
04710 0.0f, 0.5f);
04711 vproc->parameter(vp::TexGen_T, scale, 0, 0, 0);
04712 lodSphere->render(context, LODSphereMesh::Multipass,
04713 viewFrustum, ri.pixWidth, NULL);
04714 vproc->disable();
04715
04716
04717 if (ri.useTexEnvCombine)
04718 {
04719 float color[4] = { 0, 0, 0, 0 };
04720 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
04721 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
04722 }
04723
04724 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
04725 glDisable(GL_BLEND);
04726 }
04727
04728
04729 void Renderer::renderLocations(const vector<Location*>& locations,
04730 const Quatf& cameraOrientation,
04731 const Point3f& positionf,
04732 const Quatf& orientation,
04733 float scale)
04734 {
04735 if (font == NULL)
04736 return;
04737
04738 double winX, winY, winZ;
04739 int view[4] = { 0, 0, 0, 0 };
04740 view[0] = -windowWidth / 2;
04741 view[1] = -windowHeight / 2;
04742 view[2] = windowWidth;
04743 view[3] = windowHeight;
04744
04745 Vec3f viewNormal = Vec3f(0.0f, 0.0f, -1.0f) *
04746 cameraOrientation.toMatrix3();
04747 Vec3d viewNormald = Vec3d(viewNormal.x, viewNormal.y, viewNormal.z);
04748
04749 double modelview[16];
04750 double projection[16];
04751 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
04752 glGetDoublev(GL_PROJECTION_MATRIX, projection);
04753
04754 glEnable(GL_DEPTH_TEST);
04755 glEnable(GL_TEXTURE_2D);
04756 font->bind();
04757 glEnable(GL_BLEND);
04758 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04759 glDisable(GL_LIGHTING);
04760
04761 glMatrixMode(GL_PROJECTION);
04762 glPushMatrix();
04763 glLoadIdentity();
04764 glOrtho(0, windowWidth, 0, windowHeight, 1.0f, -1.0f);
04765 glMatrixMode(GL_MODELVIEW);
04766 glPushMatrix();
04767 glLoadIdentity();
04768
04769
04770
04771
04772 glTranslatef(GLfloat((int) (windowWidth / 2)),
04773 GLfloat((int) (windowHeight / 2)), -0.999f);
04774
04775 Point3d position(positionf.x, positionf.y, positionf.z);
04776 Point3d origin(0.0, 0.0, 0.0);
04777
04778 Ellipsoidd ellipsoid(position, Vec3d(scale, scale, scale));
04779
04780 float iScale = 1.0f / scale;
04781 Mat3f mat = orientation.toMatrix3();
04782
04783 for (vector<Location*>::const_iterator iter = locations.begin();
04784 iter != locations.end(); iter++)
04785 {
04786 if ((*iter)->getFeatureType() & locationFilter)
04787 {
04788
04789 Vec3f ppos = (*iter)->getPosition();
04790
04791 Vec3f pposRotated = ppos * mat;
04792
04793 Vec3d pposd(pposRotated.x, pposRotated.y, pposRotated.z);
04794
04795
04796 Point3d cpos(position + pposd * 1.0001);
04797
04798 float effSize = (*iter)->getImportance();
04799 if (effSize < 0.0f)
04800 effSize = (*iter)->getSize();
04801 float pixSize = effSize / (float) (cpos.distanceFromOrigin() * pixelSize);
04802
04803 if (pixSize > minFeatureSize &&
04804 (cpos - origin) * viewNormald > 0.0)
04805 {
04806 double r = pposd.length();
04807 if (r < scale * 0.99)
04808 cpos = position + pposd * (scale * 1.01 / r);
04809
04810 double t = 0.0f;
04811
04812
04813
04814
04815
04816
04817 bool hit = testIntersection(Ray3d(origin, cpos - origin),
04818 ellipsoid, t);
04819 if (!hit || t >= 1.0)
04820 {
04821 if (gluProject(ppos.x * iScale, ppos.y * iScale, ppos.z * iScale,
04822 modelview,
04823 projection,
04824 (const GLint*) view,
04825 &winX, &winY, &winZ) != GL_FALSE)
04826 {
04827 glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
04828 glPushMatrix();
04829 glTranslatef((int) winX + PixelOffset,
04830 (int) winY + PixelOffset,
04831 0.0f);
04832 font->render((*iter)->getName(true));
04833 glPopMatrix();
04834 }
04835 }
04836 }
04837 }
04838 }
04839
04840 glPopMatrix();
04841 glMatrixMode(GL_PROJECTION);
04842 glPopMatrix();
04843 glMatrixMode(GL_MODELVIEW);
04844 }
04845
04846
04847 static void
04848 setupObjectLighting(const vector<Renderer::LightSource>& suns,
04849 const Point3d& objPosition,
04850 const Quatf& objOrientation,
04851 const Vec3f& objScale,
04852 const Point3f& objPosition_eye,
04853 LightingState& ls)
04854 {
04855 unsigned int nLights = min(MaxLights, (unsigned int) suns.size());
04856 if (nLights == 0)
04857 return;
04858
04859 unsigned int i;
04860 for (i = 0; i < nLights; i++)
04861 {
04862 Vec3d dir = suns[i].position - objPosition;
04863 ls.lights[i].direction_eye =
04864 Vec3f((float) dir.x, (float) dir.y, (float) dir.z);
04865 float distance = ls.lights[i].direction_eye.length();
04866 ls.lights[i].direction_eye *= 1.0f / distance;
04867 distance = astro::kilometersToAU((float) dir.length());
04868 ls.lights[i].irradiance = suns[i].luminosity / (distance * distance);
04869 ls.lights[i].color = suns[i].color;
04870
04871
04872
04873 ls.lights[i].position = suns[i].position;
04874 ls.lights[i].apparentSize = (float) (suns[i].radius / dir.length());
04875 }
04876
04877
04878
04879 if (nLights == 2)
04880 {
04881 if (ls.lights[0].irradiance < ls.lights[1].irradiance)
04882 swap(ls.lights[0], ls.lights[1]);
04883 }
04884 else if (nLights > 2)
04885 {
04886 sort(ls.lights, ls.lights + nLights, LightIrradiancePredicate());
04887 }
04888
04889
04890 float totalIrradiance = 0.0f;
04891 for (i = 0; i < nLights; i++)
04892 totalIrradiance += ls.lights[i].irradiance;
04893
04894
04895
04896
04897
04898
04899
04900
04901
04902 float minVisibleFraction = 1.0f / 10000.0f;
04903 float minDisplayableValue = 1.0f / 255.0f;
04904 float gamma = (float) (log(minDisplayableValue) / log(minVisibleFraction));
04905 float minVisibleIrradiance = minVisibleFraction * totalIrradiance;
04906
04907 Mat3f m = (~objOrientation).toMatrix3();
04908
04909
04910
04911
04912 ls.nLights = 0;
04913 for (i = 0; i < nLights && ls.lights[i].irradiance > minVisibleIrradiance; i++)
04914 {
04915 ls.lights[i].irradiance =
04916 (float) pow(ls.lights[i].irradiance / totalIrradiance, gamma);
04917
04918
04919 ls.lights[i].direction_obj = ls.lights[i].direction_eye * m;
04920
04921 ls.nLights++;
04922 }
04923
04924 Point3f pos((float) objPosition.x,
04925 (float) objPosition.y,
04926 (float) objPosition.z);
04927 ls.eyePos_obj = Point3f(-objPosition_eye.x / objScale.x,
04928 -objPosition_eye.y / objScale.y,
04929 -objPosition_eye.z / objScale.z) * m;
04930 ls.eyeDir_obj = (Point3f(0.0f, 0.0f, 0.0f) - objPosition_eye) * m;
04931 ls.eyeDir_obj.normalize();
04932
04933 #if 0
04934
04935
04936
04937 float maxIrradiance = ls.lights[0].irradiance;
04938
04939
04940
04941
04942 ls.nLights = 0;
04943 for (i = 0; i < nLights; i++)
04944 {
04945 ls.lights[i].irradiance /= maxIrradiance;
04946
04947
04948
04949 if (ls.lights[i].irradiance < 1.0f / 255.0f)
04950 break;
04951
04952
04953 ls.lights[i].direction_obj = ls.lights[i].direction_eye * m;
04954
04955 ls.nLights++;
04956 }
04957 #endif
04958 }
04959
04960
04961 void Renderer::renderObject(Point3f pos,
04962 float distance,
04963 double now,
04964 Quatf cameraOrientation,
04965 float nearPlaneDistance,
04966 float farPlaneDistance,
04967 RenderProperties& obj,
04968 const LightingState& ls)
04969 {
04970 RenderInfo ri;
04971
04972 float altitude = distance - obj.radius;
04973 float discSizeInPixels = obj.radius /
04974 (max(nearPlaneDistance, altitude) * pixelSize);
04975
04976 ri.sunDir_eye = Vec3f(0.0f, 1.0f, 0.0f);
04977 ri.sunDir_obj = Vec3f(0.0f, 1.0f, 0.0f);
04978 ri.sunColor = Color(0.0f, 0.0f, 0.0f);
04979 if (ls.nLights > 0)
04980 {
04981 ri.sunDir_eye = ls.lights[0].direction_eye;
04982 ri.sunDir_obj = ls.lights[0].direction_obj;
04983 ri.sunColor = ls.lights[0].color;
04984 }
04985
04986
04987 glEnable(GL_DEPTH_TEST);
04988 glDepthMask(GL_TRUE);
04989
04990 glDisable(GL_BLEND);
04991
04992
04993 if (obj.surface->baseTexture.tex[textureResolution] != InvalidResource)
04994 ri.baseTex = obj.surface->baseTexture.find(textureResolution);
04995 if ((obj.surface->appearanceFlags & Surface::ApplyBumpMap) != 0 &&
04996 context->bumpMappingSupported() &&
04997 obj.surface->bumpTexture.tex[textureResolution] != InvalidResource)
04998 ri.bumpTex = obj.surface->bumpTexture.find(textureResolution);
04999 if ((obj.surface->appearanceFlags & Surface::ApplyNightMap) != 0 &&
05000 (renderFlags & ShowNightMaps) != 0)
05001 ri.nightTex = obj.surface->nightTexture.find(textureResolution);
05002 if ((obj.surface->appearanceFlags & Surface::SeparateSpecularMap) != 0)
05003 ri.glossTex = obj.surface->specularTexture.find(textureResolution);
05004 if ((obj.surface->appearanceFlags & Surface::ApplyOverlay) != 0)
05005 ri.overlayTex = obj.surface->overlayTexture.find(textureResolution);
05006
05007
05008 glPushMatrix();
05009 glTranslate(pos);
05010 glRotate(~obj.orientation);
05011
05012
05013
05014
05015
05016
05017
05018 float radius = obj.radius;
05019 Vec3f semiAxes = obj.radius * obj.semiAxes;
05020 glScale(semiAxes);
05021
05022 Mat4f planetMat = (~obj.orientation).toMatrix4();
05023 ri.eyeDir_obj = (Point3f(0, 0, 0) - pos) * planetMat;
05024 ri.eyeDir_obj.normalize();
05025 ri.eyePos_obj = Point3f(-pos.x / semiAxes.x,
05026 -pos.y / semiAxes.y,
05027 -pos.z / semiAxes.z) * planetMat;
05028
05029 ri.orientation = cameraOrientation;
05030
05031 ri.pixWidth = discSizeInPixels;
05032
05033
05034 if (ri.baseTex == NULL ||
05035 (obj.surface->appearanceFlags & Surface::BlendTexture) != 0)
05036 {
05037 ri.color = obj.surface->color;
05038 }
05039
05040 ri.ambientColor = ambientColor;
05041 ri.hazeColor = obj.surface->hazeColor;
05042 ri.specularColor = obj.surface->specularColor;
05043 ri.specularPower = obj.surface->specularPower;
05044 ri.useTexEnvCombine = context->getRenderPath() != GLContext::GLPath_Basic;
05045
05046
05047 bool lit = (obj.surface->appearanceFlags & Surface::Emissive) == 0;
05048
05049
05050 unsigned int i;
05051 for (i = 0; i < ls.nLights; i++)
05052 {
05053 const DirectionalLight& light = ls.lights[i];
05054
05055 glLightDirection(GL_LIGHT0 + i, ls.lights[i].direction_obj);
05056
05057
05058
05059
05060
05061
05062
05063
05064
05065
05066
05067
05068
05069
05070
05071
05072
05073
05074
05075
05076
05077
05078
05079 Vec3f lightColor = Vec3f(light.color.red(),
05080 light.color.green(),
05081 light.color.blue()) * light.irradiance;
05082 if (useRescaleNormal)
05083 {
05084 glLightColor(GL_LIGHT0 + i, GL_DIFFUSE, lightColor);
05085 glLightColor(GL_LIGHT0 + i, GL_SPECULAR, lightColor);
05086 }
05087 else
05088 {
05089 glLightColor(GL_LIGHT0 + i, GL_DIFFUSE, lightColor * radius);
05090 }
05091 glEnable(GL_LIGHT0 + i);
05092 }
05093
05094
05095 Mat4f invMV = (cameraOrientation.toMatrix4() *
05096 Mat4f::translation(Point3f(-pos.x, -pos.y, -pos.z)) *
05097 planetMat *
05098 Mat4f::scaling(1.0f / radius));
05099
05100
05101
05102 Frustum viewFrustum(degToRad(fov),
05103 (float) windowWidth / (float) windowHeight,
05104 nearPlaneDistance, farPlaneDistance);
05105 viewFrustum.transform(invMV);
05106
05107
05108 if (obj.rings != NULL)
05109 {
05110 if (ri.pixWidth > 5000)
05111 ri.pixWidth = 5000;
05112 }
05113
05114 Model* model = NULL;
05115 if (obj.model == InvalidResource)
05116 {
05117
05118 if (lit)
05119 {
05120 switch (context->getRenderPath())
05121 {
05122 case GLContext::GLPath_GLSL:
05123 renderSphere_GLSL(ri, ls, obj.rings, obj.radius,
05124 planetMat, viewFrustum, *context);
05125 break;
05126
05127 case GLContext::GLPath_NV30:
05128 renderSphere_FP_VP(ri, viewFrustum, *context);
05129 break;
05130
05131 case GLContext::GLPath_NvCombiner_ARBVP:
05132 case GLContext::GLPath_NvCombiner_NvVP:
05133 renderSphere_Combiners_VP(ri, ls, viewFrustum, *context);
05134 break;
05135
05136 case GLContext::GLPath_NvCombiner:
05137 renderSphere_Combiners(ri, viewFrustum, *context);
05138 break;
05139
05140 case GLContext::GLPath_DOT3_ARBVP:
05141 renderSphere_DOT3_VP(ri, ls, viewFrustum, *context);
05142 break;
05143
05144 default:
05145 renderSphereDefault(ri, viewFrustum, true, *context);
05146 }
05147 }
05148 else
05149 {
05150 renderSphereDefault(ri, viewFrustum, false, *context);
05151 }
05152 }
05153 else
05154 {
05155
05156 model = GetModelManager()->find(obj.model);
05157 if (model != NULL)
05158 renderModelDefault(model, ri, lit);
05159 }
05160
05161 if (obj.rings != NULL && distance <= obj.rings->innerRadius)
05162 {
05163 if (context->getRenderPath() == GLContext::GLPath_GLSL)
05164 {
05165 renderRings_GLSL(*obj.rings, ri, ls,
05166 radius, 1.0f - obj.semiAxes.y,
05167 textureResolution,
05168 (renderFlags & ShowRingShadows) != 0 && lit,
05169 detailOptions.ringSystemSections);
05170 }
05171 else
05172 {
05173 renderRings(*obj.rings, ri, radius, 1.0f - obj.semiAxes.y,
05174 textureResolution,
05175 context->getMaxTextures() > 1 &&
05176 (renderFlags & ShowRingShadows) != 0 && lit,
05177 *context,
05178 detailOptions.ringSystemSections);
05179 }
05180 }
05181
05182 if (obj.atmosphere != NULL)
05183 {
05184 Atmosphere* atmosphere = const_cast<Atmosphere *>(obj.atmosphere);
05185
05186
05187
05188
05189
05190 float fade;
05191 float thicknessInPixels = 0.0f;
05192 if (distance - radius > 0.0f)
05193 {
05194 thicknessInPixels = atmosphere->height /
05195 ((distance - radius) * pixelSize);
05196 fade = clamp(thicknessInPixels - 2);
05197 }
05198 else
05199 {
05200 fade = 1.0f;
05201 }
05202
05203 if (fade > 0 && (renderFlags & ShowAtmospheres) != 0)
05204 {
05205 glPushMatrix();
05206 glLoadIdentity();
05207 glDisable(GL_LIGHTING);
05208 glDisable(GL_TEXTURE_2D);
05209 glEnable(GL_BLEND);
05210 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
05211
05212 #ifdef OLD_ATMOSPHERE
05213 renderAtmosphere(*atmosphere,
05214 pos * (~cameraOrientation).toMatrix3(),
05215 radius,
05216 ri.sunDir_eye * (~cameraOrientation).toMatrix3(),
05217 ri.ambientColor,
05218 fade,
05219 lit);
05220 #else
05221 glRotate(cameraOrientation);
05222 renderEllipsoidAtmosphere(*atmosphere,
05223 pos,
05224 obj.orientation,
05225 semiAxes,
05226 ri.sunDir_eye,
05227 ri.ambientColor,
05228 thicknessInPixels,
05229 lit);
05230 #endif // OLD_ATMOSPHERE
05231 glEnable(GL_TEXTURE_2D);
05232 glPopMatrix();
05233 }
05234
05235
05236 Texture* cloudTex = NULL;
05237 if ((renderFlags & ShowCloudMaps) != 0 &&
05238 atmosphere->cloudTexture.tex[textureResolution] != InvalidResource)
05239 cloudTex = atmosphere->cloudTexture.find(textureResolution);
05240
05241 if (cloudTex != NULL)
05242 {
05243 glPushMatrix();
05244
05245 float cloudScale = 1.0f + atmosphere->cloudHeight / radius;
05246 glScalef(cloudScale, cloudScale, cloudScale);
05247
05248
05249
05250 if (distance - radius < atmosphere->cloudHeight)
05251 glFrontFace(GL_CW);
05252
05253 float texOffset = (float) (-pfmod(now * atmosphere->cloudSpeed / (2 * PI), 1.0));
05254 if (atmosphere->cloudSpeed != 0.0f)
05255 {
05256
05257
05258
05259
05260
05261 glMatrixMode(GL_TEXTURE);
05262 glTranslatef(texOffset, 0.0f, 0.0f);
05263 glMatrixMode(GL_MODELVIEW);
05264 }
05265
05266 glEnable(GL_LIGHTING);
05267 glDepthMask(GL_FALSE);
05268 cloudTex->bind();
05269 glEnable(GL_BLEND);
05270 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
05271 glColor4f(1, 1, 1, 1);
05272
05273 if (lit)
05274 {
05275 if (context->getRenderPath() == GLContext::GLPath_GLSL)
05276 {
05277 renderClouds_GLSL(ri, ls,
05278 cloudTex,
05279 texOffset,
05280 obj.rings,
05281 radius * cloudScale,
05282 planetMat,
05283 viewFrustum,
05284 *context);
05285 }
05286 else
05287 {
05288 VertexProcessor* vproc = context->getVertexProcessor();
05289 if (vproc != NULL)
05290 {
05291 vproc->enable();
05292 vproc->parameter(vp::AmbientColor, ri.ambientColor * ri.color);
05293 vproc->parameter(vp::TextureTranslation,
05294 texOffset, 0.0f, 0.0f, 0.0f);
05295 if (ls.nLights > 1)
05296 vproc->use(vp::diffuseTexOffset_2light);
05297 else
05298 vproc->use(vp::diffuseTexOffset);
05299 setLightParameters_VP(*vproc, ls, ri.color, Color::Black);
05300 }
05301
05302 lodSphere->render(*context,
05303 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
05304 viewFrustum,
05305 ri.pixWidth,
05306 cloudTex);
05307
05308 if (vproc != NULL)
05309 vproc->disable();
05310 }
05311 }
05312 else
05313 {
05314 glDisable(GL_LIGHTING);
05315 lodSphere->render(*context,
05316 LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
05317 viewFrustum,
05318 ri.pixWidth,
05319 cloudTex);
05320 glEnable(GL_LIGHTING);
05321 }
05322
05323
05324 glMatrixMode(GL_TEXTURE);
05325 glLoadIdentity();
05326 glMatrixMode(GL_MODELVIEW);
05327
05328 glDepthMask(GL_TRUE);
05329 glFrontFace(GL_CCW);
05330
05331 glPopMatrix();
05332 }
05333 }
05334
05335
05336 if (ls.shadows[0] != NULL &&
05337 ls.shadows[0]->size() != 0 &&
05338 (obj.surface->appearanceFlags & Surface::Emissive) == 0 &&
05339 context->getRenderPath() != GLContext::GLPath_GLSL)
05340 {
05341 #if 1
05342
05343 if (context->getVertexProcessor() != NULL &&
05344 context->getFragmentProcessor() != NULL)
05345 {
05346 renderEclipseShadows_Shaders(model,
05347 *ls.shadows[0],
05348 ri,
05349 radius, planetMat, viewFrustum,
05350 *context);
05351 }
05352 else
05353 #endif
05354 {
05355 renderEclipseShadows(model,
05356 *ls.shadows[0],
05357 ri,
05358 radius, planetMat, viewFrustum,
05359 *context);
05360 }
05361 }
05362
05363 if (obj.rings != NULL &&
05364 (obj.surface->appearanceFlags & Surface::Emissive) == 0 &&
05365 (renderFlags & ShowRingShadows) != 0)
05366 {
05367 Texture* ringsTex = obj.rings->texture.find(textureResolution);
05368 if (ringsTex != NULL)
05369 {
05370 Vec3f sunDir = pos - Point3f(0, 0, 0);
05371 sunDir.normalize();
05372
05373 ringsTex->bind();
05374
05375 if (useClampToBorder &&
05376 context->getVertexPath() != GLContext::VPath_Basic &&
05377 context->getRenderPath() != GLContext::GLPath_GLSL)
05378 {
05379 renderRingShadowsVS(model,
05380 *obj.rings,
05381 sunDir,
05382 ri,
05383 radius, 1.0f - obj.semiAxes.y,
05384 planetMat, viewFrustum,
05385 *context);
05386 }
05387 }
05388 }
05389
05390 if (obj.rings != NULL && distance > obj.rings->innerRadius)
05391 {
05392 glDepthMask(GL_FALSE);
05393 if (context->getRenderPath() == GLContext::GLPath_GLSL)
05394 {
05395 renderRings_GLSL(*obj.rings, ri, ls,
05396 radius, 1.0f - obj.semiAxes.y,
05397 textureResolution,
05398 (renderFlags & ShowRingShadows) != 0 && lit,
05399 detailOptions.ringSystemSections);
05400 }
05401 else
05402 {
05403 renderRings(*obj.rings, ri, radius, 1.0f - obj.semiAxes.y,
05404 textureResolution,
05405 (context->hasMultitexture() &&
05406 (renderFlags & ShowRingShadows) != 0 && lit),
05407 *context,
05408 detailOptions.ringSystemSections);
05409 }
05410 }
05411
05412
05413 for (i = 0; i < ls.nLights; i++)
05414 glDisable(GL_LIGHT0 + i);
05415
05416
05417 if (obj.locations != NULL && (labelMode & LocationLabels) != 0)
05418 renderLocations(*obj.locations,
05419 cameraOrientation,
05420 pos, obj.orientation, radius);
05421
05422 glPopMatrix();
05423 glDisable(GL_DEPTH_TEST);
05424 glDepthMask(GL_FALSE);
05425 glDisable(GL_LIGHTING);
05426 glEnable(GL_BLEND);
05427 }
05428
05429
05430 bool Renderer::testEclipse(const Body& receiver,
05431 const Body& caster,
05432 const DirectionalLight& light,
05433 double now,
05434 vector<EclipseShadow>& shadows)
05435 {
05436
05437
05438
05439
05440
05441 if (caster.getRadius() * 100 >= receiver.getRadius() &&
05442 caster.getClassification() != Body::Invisible &&
05443 caster.extant(now) &&
05444 caster.getModel() == InvalidResource)
05445 {
05446
05447
05448
05449
05450
05451
05452
05453
05454 Point3d posReceiver = receiver.getHeliocentricPosition(now);
05455 Point3d posCaster = caster.getHeliocentricPosition(now);
05456
05457
05458
05459
05460
05461 float appSunRadius = light.apparentSize;
05462
05463 Vec3d dir = posCaster - posReceiver;
05464 double distToCaster = dir.length() - receiver.getRadius();
05465 float appOccluderRadius = (float) (caster.getRadius() / distToCaster);
05466
05467
05468
05469
05470
05471 float shadowRadius = (1 + appSunRadius / appOccluderRadius) *
05472 caster.getRadius();
05473
05474
05475
05476
05477
05478
05479
05480
05481
05482
05483 float R = receiver.getRadius() + shadowRadius;
05484 double dist = distance(posReceiver,
05485 Ray3d(posCaster, posCaster - light.position));
05486 if (dist < R)
05487 {
05488 Vec3d sunDir = posCaster - light.position;
05489 sunDir.normalize();
05490
05491 EclipseShadow shadow;
05492 shadow.origin = Point3f((float) dir.x,
05493 (float) dir.y,
05494 (float) dir.z);
05495 shadow.direction = Vec3f((float) sunDir.x,
05496 (float) sunDir.y,
05497 (float) sunDir.z);
05498 shadow.penumbraRadius = shadowRadius;
05499 shadow.umbraRadius = caster.getRadius() *
05500 (appOccluderRadius - appSunRadius) / appOccluderRadius;
05501 shadows.push_back(shadow);
05502
05503 return true;
05504 }
05505 }
05506
05507 return false;
05508 }
05509
05510
05511 void Renderer::renderPlanet(Body& body,
05512 Point3f pos,
05513 float distance,
05514 float appMag,
05515 double now,
05516 Quatf orientation,
05517 const vector<LightSource>& lightSources,
05518 float nearPlaneDistance,
05519 float farPlaneDistance)
05520 {
05521 float altitude = distance - body.getRadius();
05522 float discSizeInPixels = body.getRadius() /
05523 (max(nearPlaneDistance, altitude) * pixelSize);
05524
05525 if (discSizeInPixels > 1)
05526 {
05527 RenderProperties rp;
05528
05529 if (displayedSurface.empty())
05530 {
05531 rp.surface = const_cast<Surface*>(&body.getSurface());
05532 }
05533 else
05534 {
05535 rp.surface = body.getAlternateSurface(displayedSurface);
05536 if (rp.surface == NULL)
05537 rp.surface = const_cast<Surface*>(&body.getSurface());
05538 }
05539 rp.atmosphere = body.getAtmosphere();
05540 rp.rings = body.getRings();
05541 rp.radius = body.getRadius();
05542 rp.semiAxes = Vec3f(1.0f, 1.0f - body.getOblateness(), 1.0f);
05543 rp.model = body.getModel();
05544
05545
05546 Quatd q = body.getEclipticalToEquatorial(now);
05547
05548 double rotation = 0.0;
05549
05550
05551 {
05552 RotationElements re = body.getRotationElements();
05553 double rotations = (now - re.epoch) / (double) re.period;
05554 double wholeRotations = floor(rotations);
05555 double remainder = rotations - wholeRotations;
05556
05557
05558
05559
05560 remainder += 0.5;
05561
05562 rotation = remainder * 2 * PI + re.offset;
05563 }
05564 q.yrotate(-rotation);
05565 rp.orientation = body.getOrientation() *
05566 Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z);
05567
05568 rp.locations = body.getLocations();
05569 if (rp.locations != NULL && (labelMode & LocationLabels) != 0)
05570 body.computeLocations();
05571
05572 LightingState lights;
05573 setupObjectLighting(lightSources,
05574 body.getHeliocentricPosition(now),
05575 rp.orientation,
05576 rp.semiAxes,
05577 pos,
05578 lights);
05579 assert(lights.nLights < MaxLights);
05580
05581 {
05582
05583 for (unsigned int li = 0; li < lights.nLights; li++)
05584 {
05585 eclipseShadows[li].clear();
05586 lights.shadows[li] = &eclipseShadows[li];
05587 }
05588 }
05589
05590
05591
05592 if ((renderFlags & ShowEclipseShadows) != 0 &&
05593 body.getClassification() != Body::Invisible &&
05594 body.getSystem() != NULL)
05595 {
05596 PlanetarySystem* system = body.getSystem();
05597
05598 if (system->getPrimaryBody() == NULL &&
05599 body.getSatellites() != NULL)
05600 {
05601
05602
05603 PlanetarySystem* satellites = body.getSatellites();
05604 if (satellites != NULL)
05605 {
05606 int nSatellites = satellites->getSystemSize();
05607 for (unsigned int li = 0; li < lights.nLights; li++)
05608 {
05609 for (int i = 0; i < nSatellites; i++)
05610 testEclipse(body, *satellites->getBody(i),
05611 lights.lights[li],
05612 now, *lights.shadows[li]);
05613 }
05614 }
05615 }
05616 else if (system->getPrimaryBody() != NULL)
05617 {
05618 for (unsigned int li = 0; li < lights.nLights; li++)
05619 {
05620
05621
05622 Body* planet = system->getPrimaryBody();
05623 testEclipse(body, *planet, lights.lights[li],
05624 now, *lights.shadows[li]);
05625
05626 int nSatellites = system->getSystemSize();
05627 for (int i = 0; i < nSatellites; i++)
05628 {
05629 if (system->getBody(i) != &body)
05630 {
05631 testEclipse(body, *system->getBody(i),
05632 lights.lights[li],
05633 now, *lights.shadows[li]);
05634 }
05635 }
05636 }
05637 }
05638 }
05639
05640 renderObject(pos, distance, now,
05641 orientation, nearPlaneDistance, farPlaneDistance,
05642 rp, lights);
05643
05644
05645 if ((renderFlags & ShowCelestialSphere) != 0 &&
05646 rp.model == InvalidResource &&
05647 discSizeInPixels > 100.0f)
05648 {
05649 glPushMatrix();
05650 glLoadIdentity();
05651 glDisable(GL_TEXTURE_2D);
05652 glRotate(orientation);
05653
05654 Vec3f semiAxes = rp.semiAxes * rp.radius;
05655
05656
05657 Quatd q = body.getEclipticalToEquatorial(now);
05658 Quatf qf = Quatf((float) q.w, (float) q.x, (float) q.y,
05659 (float) q.z);
05660
05661 if ((renderFlags & ShowSmoothLines) != 0)
05662 enableSmoothLines();
05663 renderCompass(pos, qf, semiAxes, pixelSize / rp.radius);
05664 if ((renderFlags & ShowSmoothLines) != 0)
05665 disableSmoothLines();
05666
05667 glEnable(GL_TEXTURE_2D);
05668 glPopMatrix();
05669 }
05670 }
05671
05672 glEnable(GL_TEXTURE_2D);
05673 glEnable(GL_BLEND);
05674 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
05675 renderBodyAsParticle(pos,
05676 appMag,
05677 faintestPlanetMag,
05678 discSizeInPixels,
05679 body.getSurface().color,
05680 orientation,
05681 (nearPlaneDistance + farPlaneDistance) / 2.0f,
05682 false);
05683 }
05684
05685
05686 void Renderer::renderStar(const Star& star,
05687 Point3f pos,
05688 float distance,
05689 float appMag,
05690 Quatf orientation,
05691 double now,
05692 float nearPlaneDistance,
05693 float farPlaneDistance)
05694 {
05695 if (!star.getVisibility())
05696 return;
05697
05698
05699 Color color = colorTemp->lookupColor(star.getTemperature());
05700 float radius = star.getRadius();
05701 float discSizeInPixels = radius / (distance * pixelSize);
05702
05703 if (discSizeInPixels > 1)
05704 {
05705 Surface surface;
05706 RenderProperties rp;
05707
05708 surface.color = color;
05709
05710 MultiResTexture mtex = star.getTexture();
05711 if (mtex.tex[textureResolution] != InvalidResource)
05712 {
05713 surface.baseTexture = mtex;
05714 }
05715 else
05716 {
05717 surface.baseTexture = InvalidResource;
05718 }
05719 surface.appearanceFlags |= Surface::ApplyBaseTexture;
05720 surface.appearanceFlags |= Surface::Emissive;
05721
05722 rp.surface = &surface;
05723 rp.rings = NULL;
05724 rp.radius = star.getRadius();
05725 rp.semiAxes = star.getEllipsoidSemiAxes();
05726 rp.model = star.getModel();
05727
05728 Atmosphere atmosphere;
05729 atmosphere.height = radius * CoronaHeight;
05730 atmosphere.lowerColor = color;
05731 atmosphere.upperColor = color;
05732 atmosphere.skyColor = color;
05733 if (rp.model == InvalidResource)
05734 rp.atmosphere = &atmosphere;
05735 else
05736 rp.atmosphere = NULL;
05737
05738 const RotationElements& re = star.getRotationElements();
05739 Quatd q = re.eclipticalToEquatorial(now);
05740
05741 double rotation = 0.0;
05742
05743
05744 {
05745 const RotationElements& re = star.getRotationElements();
05746 double rotations = (now - re.epoch) / (double) re.period;
05747 double wholeRotations = floor(rotations);
05748 double remainder = rotations - wholeRotations;
05749
05750
05751
05752
05753 remainder += 0.5;
05754
05755 rotation = remainder * 2 * PI + re.offset;
05756 }
05757 q.yrotate(-rotation);
05758 rp.orientation = Quatf((float) q.w, (float) q.x, (float) q.y, (float) q.z);
05759
05760 renderObject(pos, distance, now,
05761 orientation, nearPlaneDistance, farPlaneDistance,
05762 rp, LightingState());
05763
05764 glEnable(GL_TEXTURE_2D);
05765 }
05766
05767 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
05768 renderBodyAsParticle(pos,
05769 appMag,
05770 faintestMag,
05771 discSizeInPixels,
05772 color,
05773 orientation,
05774 (nearPlaneDistance + farPlaneDistance) / 2.0f,
05775 true);
05776 }
05777
05778
05779 static const int MaxCometTailPoints = 20;
05780 static const int CometTailSlices = 16;
05781 struct CometTailVertex
05782 {
05783 Point3f point;
05784 Vec3f normal;
05785 Point3f paraboloidPoint;
05786 float brightness;
05787 };
05788
05789 static CometTailVertex cometTailVertices[CometTailSlices * MaxCometTailPoints];
05790
05791 static void ProcessCometTailVertex(const CometTailVertex& v,
05792 const Vec3f& viewDir,
05793 float fadeDistFromSun)
05794 {
05795
05796
05797
05798 float fadeFactor = 0.5f - 0.5f * tanh(fadeDistFromSun - 1.0f / fadeDistFromSun);
05799 float shade = abs(viewDir * v.normal * v.brightness * fadeFactor);
05800 glColor4f(0.5f, 0.5f, 0.75f, shade);
05801 glVertex(v.point);
05802 }
05803
05804 static void ProcessCometTailVertex(const CometTailVertex& v,
05805 const Point3f& cameraPos)
05806 {
05807 Vec3f viewDir = v.point - cameraPos;
05808 viewDir.normalize();
05809 float shade = abs(viewDir * v.normal * v.brightness);
05810 glColor4f(0.0f, 0.5f, 1.0f, shade);
05811 glVertex(v.point);
05812 }
05813
05814
05815 static void ProcessCometTailVertex(const CometTailVertex& v,
05816 const Point3f& eyePos_obj,
05817 float b,
05818 float h)
05819 {
05820 float shade = 0.0f;
05821 Vec3f R = v.paraboloidPoint - eyePos_obj;
05822 float c0 = b * (square(eyePos_obj.x) + square(eyePos_obj.y)) + eyePos_obj.z;
05823 float c1 = 2 * b * (R.x * eyePos_obj.x + R.y * eyePos_obj.y) - R.z;
05824 float c2 = b * (square(R.x) + square(R.y));
05825
05826 float disc = square(c1) - 4 * c0 * c2;
05827
05828 if (disc < 0.0f)
05829 {
05830 shade = 0.0f;
05831 }
05832 else
05833 {
05834 disc = (float) sqrt(disc);
05835 float s = 1.0f / (2 * c2);
05836 float t0 = (h - eyePos_obj.z) / R.z;
05837 float t1 = (c1 - disc) * s;
05838 float t2 = (c1 + disc) * s;
05839 float u0 = max(t0, 0.0f);
05840 float u1, u2;
05841
05842 if (R.z < 0.0f)
05843 {
05844 u1 = max(t1, t0);
05845 u2 = max(t2, t0);
05846 }
05847 else
05848 {
05849 u1 = min(t1, t0);
05850 u2 = min(t2, t0);
05851 }
05852 u1 = max(0.0f, u1);
05853 u2 = max(0.0f, u2);
05854
05855 shade = u2 - u1;
05856 }
05857
05858 glColor4f(0.0f, 0.5f, 1.0f, shade);
05859 glVertex(v.point);
05860 }
05861
05862
05863 void Renderer::renderCometTail(const Body& body,
05864 Point3f pos,
05865 float distance,
05866 float appMag,
05867 double now,
05868 Quatf orientation,
05869 const vector<LightSource>& lightSources,
05870 float nearPlaneDistance,
05871 float farPlaneDistance)
05872 {
05873 Point3f cometPoints[MaxCometTailPoints];
05874 Point3d pos0 = body.getOrbit()->positionAtTime(now);
05875 Point3d pos1 = body.getOrbit()->positionAtTime(now - 0.01);
05876 Vec3d vd = pos1 - pos0;
05877 double t = now;
05878 float f = 1.0e15f;
05879 int nSteps = MaxCometTailPoints;
05880 float dt = 10000000.0f / (nSteps * (float) vd.length() * 100.0f);
05881 float distanceFromSun, irradiance_max = 0.0f;
05882 unsigned int li_eff;
05883
05884
05885
05886
05887
05888 for (unsigned int li = 0; li < lightSources.size(); li++)
05889 {
05890 distanceFromSun = (float)(body.getHeliocentricPosition(now) -
05891 lightSources[li].position).length();
05892 float irradiance = lightSources[li].luminosity / square(distanceFromSun);
05893 if (irradiance > irradiance_max )
05894 {
05895 li_eff = li;
05896 irradiance_max = irradiance;
05897 }
05898 }
05899 float fadeDistance = 1.0f / (X0_SOL * sqrt(irradiance_max));
05900
05901
05902
05903 Vec3d sd = body.getHeliocentricPosition(now) - lightSources[li_eff].position;
05904 Vec3f sunDir = Vec3f((float) sd.x, (float) sd.y, (float) sd.z);
05905 sunDir.normalize();
05906
05907
05908
05909 int i;
05910 #if 0
05911 for (i = 0; i < MaxCometTailPoints; i++)
05912 {
05913 Vec3d pd = body.getOrbit()->positionAtTime(t) - pos0;
05914 Point3f p = Point3f((float) pd.x, (float) pd.y, (float) pd.z);
05915 Vec3f r(p.x + (float) pos0.x,
05916 p.y + (float) pos0.y,
05917 p.z + (float) pos0.z);
05918 float distance = r.length();
05919
05920 Vec3f a = r * ((1 / square(distance)) * f * dt);
05921 Vec3f dx = a * (square(i * dt) * 0.5f);
05922
05923 cometPoints[i] = p + dx;
05924
05925 t -= dt;
05926 }
05927 #endif
05928
05929
05930 float dustTailLength = (1.0e8f / (float) pos0.distanceFromOrigin()) *
05931 (body.getRadius() / 5.0f) * 1.0e7f;
05932 float dustTailRadius = dustTailLength * 0.1f;
05933 float comaRadius = dustTailRadius * 0.5f;
05934
05935 Point3f origin(0, 0, 0);
05936 origin -= sunDir * (body.getRadius() * 100);
05937 for (i = 0; i < MaxCometTailPoints; i++)
05938 {
05939 float alpha = (float) i / (float) MaxCometTailPoints;
05940 alpha = alpha * alpha;
05941 cometPoints[i] = origin + sunDir * (dustTailLength * alpha);
05942 }
05943
05944
05945
05946
05947
05948 Quatd qd = body.getEclipticalToEquatorial(t);
05949 Quatf q((float) qd.w, (float) qd.x, (float) qd.y, (float) qd.z);
05950 Vec3f v = cometPoints[1] - cometPoints[0];
05951 v.normalize();
05952 Vec3f u0 = Vec3f(0, 1, 0) * q.toMatrix3();
05953 Vec3f u1 = Vec3f(1, 0, 0) * q.toMatrix3();
05954 Vec3f u;
05955 if (abs(u0 * v) < abs(u1 * v))
05956 u = v ^ u0;
05957 else
05958 u = v ^ u1;
05959 u.normalize();
05960 Vec3f w = u ^ v;
05961
05962 glColor4f(0.0f, 1.0f, 1.0f, 0.5f);
05963 glPushMatrix();
05964 glTranslate(pos);
05965
05966
05967 glDisable(GL_TEXTURE_2D);
05968 glDisable(GL_LIGHTING);
05969 glDepthMask(GL_FALSE);
05970 glEnable(GL_BLEND);
05971 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
05972
05973 for (i = 0; i < MaxCometTailPoints; i++)
05974 {
05975 float brightness = 1.0f - (float) i / (float) (MaxCometTailPoints - 1);
05976 Vec3f v0, v1;
05977 float sectionLength;
05978 if (i != 0 && i != MaxCometTailPoints - 1)
05979 {
05980 v0 = cometPoints[i] - cometPoints[i - 1];
05981 v1 = cometPoints[i + 1] - cometPoints[i];
05982 sectionLength = v0.length();
05983 v0.normalize();
05984 v1.normalize();
05985 Vec3f axis = v1 ^ v0;
05986 float axisLength = axis.length();
05987 if (axisLength > 1e-5f)
05988 {
05989 axis *= 1.0f / axisLength;
05990 q.setAxisAngle(axis, (float) asin(axisLength));
05991 Mat3f m = q.toMatrix3();
05992
05993 u = u * m;
05994 v = v * m;
05995 w = w * m;
05996 }
05997 }
05998 else if (i == 0)
05999 {
06000 v0 = cometPoints[i + 1] - cometPoints[i];
06001 sectionLength = v0.length();
06002 v0.normalize();
06003 v1 = v0;
06004 }
06005 else
06006 {
06007 v0 = v1 = cometPoints[i] - cometPoints[i - 1];
06008 sectionLength = v0.length();
06009 v0.normalize();
06010 v1 = v0;
06011 }
06012
06013 float radius = (float) i / (float) MaxCometTailPoints *
06014 dustTailRadius;
06015 float dr = (dustTailRadius / (float) MaxCometTailPoints) /
06016 sectionLength;
06017 float w0 = (float) atan(dr);
06018 float w1 = (float) sqrt(1.0f - square(w0));
06019
06020 for (int j = 0; j < CometTailSlices; j++)
06021 {
06022 float theta = (float) (2 * PI * (float) j / CometTailSlices);
06023 float s = (float) sin(theta);
06024 float c = (float) cos(theta);
06025 CometTailVertex* vtx = &cometTailVertices[i * CometTailSlices + j];
06026 vtx->normal = u * (s * w1) + w * (c * w1) + v * w0;
06027 s *= radius;
06028 c *= radius;
06029
06030 vtx->point = Point3f(cometPoints[i].x + u.x * s + w.x * c,
06031 cometPoints[i].y + u.y * s + w.y * c,
06032 cometPoints[i].z + u.z * s + w.z * c);
06033 vtx->brightness = brightness;
06034 vtx->paraboloidPoint =
06035 Point3f(c, s, square((float) i / (float) MaxCometTailPoints));
06036 }
06037 }
06038
06039 Vec3f viewDir = pos - Point3f(0.0f, 0.0f, 0.0f);
06040 viewDir.normalize();
06041
06042 glDisable(GL_CULL_FACE);
06043 for (i = 0; i < MaxCometTailPoints - 1; i++)
06044 {
06045 glBegin(GL_QUAD_STRIP);
06046 int n = i * CometTailSlices;
06047 for (int j = 0; j < CometTailSlices; j++)
06048 {
06049 ProcessCometTailVertex(cometTailVertices[n + j], viewDir, fadeDistance);
06050 ProcessCometTailVertex(cometTailVertices[n + j + CometTailSlices],
06051 viewDir, fadeDistance);
06052 }
06053 ProcessCometTailVertex(cometTailVertices[n], viewDir, fadeDistance);
06054 ProcessCometTailVertex(cometTailVertices[n + CometTailSlices],
06055 viewDir, fadeDistance);
06056 glEnd();
06057 }
06058 glEnable(GL_CULL_FACE);
06059
06060 glBegin(GL_LINE_STRIP);
06061 for (i = 0; i < MaxCometTailPoints; i++)
06062 {
06063 glVertex(cometPoints[i]);
06064 }
06065 glEnd();
06066
06067 glDepthMask(GL_TRUE);
06068 glEnable(GL_TEXTURE_2D);
06069 glEnable(GL_BLEND);
06070
06071 glPopMatrix();
06072 }
06073
06074
06075 void Renderer::renderPlanetarySystem(const Star& sun,
06076 const PlanetarySystem& solSystem,
06077 const Observer& observer,
06078 double now,
06079 unsigned int solarSysIndex,
06080 bool showLabels)
06081 {
06082 Point3f starPos = sun.getPosition();
06083 Point3d observerPos = astrocentricPosition(observer.getPosition(),
06084 sun, now);
06085
06086 int nBodies = solSystem.getSystemSize();
06087 for (int i = 0; i < nBodies; i++)
06088 {
06089 Body* body = solSystem.getBody(i);
06090 if (!body->extant(now))
06091 continue;
06092
06093 Point3d localPos = body->getOrbit()->positionAtTime(now);
06094 Point3d bodyPos = body->getHeliocentricPosition(now);
06095
06096
06097
06098
06099 Vec3d posd = bodyPos - observerPos;
06100
06101 vector<LightSource>& lightSources = lightSourceLists[solarSysIndex];
06102
06103
06104
06105
06106 float appMag = 100.0f;
06107 for (unsigned int li = 0; li < lightSources.size(); li++)
06108 {
06109 Vec3d sunPos = bodyPos - lightSources[li].position;
06110 appMag = min(appMag, body->getApparentMagnitude(lightSources[li].luminosity, sunPos, posd));
06111 }
06112
06113 Vec3f pos((float) posd.x, (float) posd.y, (float) posd.z);
06114
06115
06116 double distanceFromObserver = posd.length();
06117 float discSize = (body->getRadius() / (float) distanceFromObserver) / pixelSize;
06118
06119
06120 if ((discSize > 1 || appMag < faintestPlanetMag) &&
06121 body->getClassification() != Body::Invisible)
06122 {
06123 RenderListEntry rle;
06124 rle.body = body;
06125 rle.star = NULL;
06126 rle.isCometTail = false;
06127 rle.position = Point3f(pos.x, pos.y, pos.z);
06128 rle.sun = Vec3f((float) -bodyPos.x, (float) -bodyPos.y, (float) -bodyPos.z);
06129 rle.distance = (float) distanceFromObserver;
06130 rle.radius = body->getRadius();
06131 rle.discSizeInPixels = discSize;
06132 rle.appMag = appMag;
06133 rle.solarSysIndex = solarSysIndex;
06134 renderList.insert(renderList.end(), rle);
06135 }
06136
06137 if (body->getClassification() == Body::Comet &&
06138 (renderFlags & ShowCometTails) != 0)
06139 {
06140 float radius = 10000000.0f;
06141 discSize = (radius / (float) distanceFromObserver) / pixelSize;
06142 if (discSize > 1)
06143 {
06144 RenderListEntry rle;
06145 rle.body = body;
06146 rle.star = NULL;
06147 rle.isCometTail = true;
06148 rle.position = Point3f(pos.x, pos.y, pos.z);
06149 rle.radius = radius;
06150 rle.sun = Vec3f((float) -bodyPos.x, (float) -bodyPos.y, (float) -bodyPos.z);
06151 rle.distance = (float) distanceFromObserver;
06152 rle.radius = radius;
06153 rle.discSizeInPixels = discSize;
06154 rle.appMag = appMag;
06155 rle.solarSysIndex = solarSysIndex;
06156 renderList.insert(renderList.end(), rle);
06157 }
06158 }
06159
06160 if (showLabels && (pos * conjugate(observer.getOrientation()).toMatrix3()).z < 0)
06161 {
06162 float boundingRadiusSize = (float) (body->getOrbit()->getBoundingRadius() / distanceFromObserver) / pixelSize;
06163 if (boundingRadiusSize > minOrbitSize)
06164 {
06165 Color labelColor;
06166 bool showLabel = false;
06167
06168 switch (body->getClassification())
06169 {
06170 case Body::Planet:
06171 if ((labelMode & PlanetLabels) != 0)
06172 {
06173 labelColor = Color(0.0f, 1.0f, 0.0f);
06174 showLabel = true;
06175 }
06176 break;
06177 case Body::Moon:
06178 if ((labelMode & MoonLabels) != 0)
06179 {
06180 labelColor = Color(0.0f, 0.65f, 0.0f);
06181 showLabel = true;
06182 }
06183 break;
06184 case Body::Asteroid:
06185 if ((labelMode & AsteroidLabels) != 0)
06186 {
06187 labelColor = Color(0.7f, 0.4f, 0.0f);
06188 showLabel = true;
06189 }
06190 break;
06191 case Body::Comet:
06192 if ((labelMode & CometLabels) != 0)
06193 {
06194 labelColor = Color(0.0f, 1.0f, 1.0f);
06195 showLabel = true;
06196 }
06197 break;
06198 case Body::Spacecraft:
06199 if ((labelMode & SpacecraftLabels) != 0)
06200 {
06201 labelColor = Color(0.6f, 0.6f, 0.6f);
06202 showLabel = true;
06203 }
06204 break;
06205 }
06206
06207 if (showLabel)
06208 {
06209 addSortedLabel(body->getName(), labelColor,
06210 Point3f(pos.x, pos.y, pos.z));
06211 }
06212 }
06213 }
06214
06215 if (appMag < faintestPlanetMag)
06216 {
06217 const PlanetarySystem* satellites = body->getSatellites();
06218 if (satellites != NULL)
06219 {
06220 renderPlanetarySystem(sun, *satellites, observer,
06221 now, solarSysIndex, showLabels);
06222 }
06223 }
06224 }
06225 }
06226
06227
06228
06229
06230 template <class OBJ, class PREC> class ObjectRenderer : public OctreeProcessor<OBJ, PREC>
06231 {
06232 public:
06233 ObjectRenderer(const PREC distanceLimit);
06234
06235 void process(const OBJ&, PREC, float) {};
06236
06237 public:
06238 const Observer* observer;
06239
06240 GLContext* context;
06241 Renderer* renderer;
06242
06243 Vec3f viewNormal;
06244
06245 float fov;
06246 float size;
06247 float pixelSize;
06248 float faintestMag;
06249 float faintestMagNight;
06250 float saturationMag;
06251 float brightnessScale;
06252 float brightnessBias;
06253 float distanceLimit;
06254
06255
06256
06257
06258 int nRendered;
06259 int nClose;
06260 int nBright;
06261 int nProcessed;
06262 int nLabelled;
06263
06264 int renderFlags;
06265 int labelMode;
06266 };
06267
06268
06269 template <class OBJ, class PREC>
06270 ObjectRenderer<OBJ, PREC>::ObjectRenderer(const PREC _distanceLimit) :
06271 distanceLimit((float) _distanceLimit),
06272 nRendered (0),
06273 nClose (0),
06274 nBright (0),
06275 nProcessed (0),
06276 nLabelled (0)
06277 {
06278 }
06279
06280
06281
06282
06283 class StarRenderer : public ObjectRenderer<Star, float>
06284 {
06285 public:
06286 StarRenderer();
06287
06288 void process(const Star& star, float distance, float appMag);
06289
06290 public:
06291 Point3f obsPos;
06292
06293 vector<Renderer::Particle>* glareParticles;
06294 vector<RenderListEntry>* renderList;
06295 Renderer::StarVertexBuffer* starVertexBuffer;
06296
06297 bool useDiscs;
06298 float maxDiscSize;
06299
06300 const ColorTemperatureTable* colorTemp;
06301 };
06302
06303
06304 StarRenderer::StarRenderer() :
06305 ObjectRenderer<Star, float>(STAR_DISTANCE_LIMIT),
06306 starVertexBuffer(0),
06307 useDiscs (false),
06308 maxDiscSize (1.0f),
06309 colorTemp (NULL)
06310 {
06311 }
06312
06313
06314 void StarRenderer::process(const Star& star, float distance, float appMag)
06315 {
06316 nProcessed++;
06317
06318 Point3f starPos = star.getPosition();
06319 Vec3f relPos = starPos - obsPos;
06320 float orbitalRadius = star.getOrbitalRadius();
06321 bool hasOrbit = orbitalRadius > 0.0f;
06322
06323 if (distance > distanceLimit)
06324 return;
06325
06326 if (relPos * viewNormal > 0 || relPos.x * relPos.x < 0.1f || hasOrbit)
06327 {
06328 Color starColor = colorTemp->lookupColor(star.getTemperature());
06329 float renderDistance = distance;
06330 float s = renderDistance * size;
06331 float discSizeInPixels = 0.0f;
06332 float orbitSizeInPixels = 0.0f;
06333
06334 if (hasOrbit)
06335 orbitSizeInPixels = orbitalRadius / (distance * pixelSize);
06336
06337
06338
06339
06340
06341
06342
06343
06344
06345
06346
06347 if (distance < 1.0f || orbitSizeInPixels > 1.0f)
06348 {
06349
06350
06351
06352
06353 Point3d hPos = astrocentricPosition(observer->getPosition(),
06354 star,
06355 observer->getTime());
06356 relPos = Vec3f((float) hPos.x, (float) hPos.y, (float) hPos.z) *
06357 -astro::kilometersToLightYears(1.0f),
06358 distance = relPos.length();
06359
06360
06361 appMag = astro::absToAppMag(star.getAbsoluteMagnitude(), distance);
06362
06363 float f = RenderDistance / distance;
06364 renderDistance = RenderDistance;
06365 starPos = obsPos + relPos * f;
06366
06367 float radius = star.getRadius();
06368 discSizeInPixels = radius / astro::lightYearsToKilometers(distance) / pixelSize;
06369 ++nClose;
06370 }
06371
06372 if (discSizeInPixels <= 1)
06373 {
06374 float alpha = (faintestMag - appMag) * brightnessScale + brightnessBias;
06375
06376 if (useDiscs)
06377 {
06378 float discSize = size;
06379 if (alpha < 0.0f)
06380 {
06381 alpha = 0.0f;
06382 }
06383 else if (alpha > 1.0f)
06384 {
06385 discSize = min(discSize * (2.0f * alpha - 1.0f), maxDiscSize);
06386 alpha = 1.0f;
06387 }
06388 starVertexBuffer->addStar(starPos,
06389 Color(starColor, alpha),
06390 renderDistance * discSize);
06391 }
06392 else
06393 {
06394 alpha = clamp(alpha);
06395 starVertexBuffer->addStar(starPos,
06396 Color(starColor, alpha),
06397 renderDistance * size);
06398 }
06399
06400 ++nRendered;
06401
06402
06403
06404
06405 if (appMag < saturationMag)
06406 {
06407 Renderer::Particle p;
06408 p.center = starPos;
06409 p.size = renderDistance * size;
06410 p.color = Color(starColor, alpha);
06411
06412 alpha = 0.4f * clamp((appMag - saturationMag) * -0.8f);
06413 s = renderDistance * 0.001f * (3 - (appMag - saturationMag)) * 2;
06414 if (s > p.size * 3 )
06415 p.size = s * 2.0f/(1.0f + FOV/fov);
06416 else
06417 p.size = p.size * 3;
06418 p.color = Color(starColor, alpha);
06419 glareParticles->insert(glareParticles->end(), p);
06420 ++nBright;
06421 }
06422 }
06423 else
06424 {
06425 RenderListEntry rle;
06426 rle.star = ☆
06427 rle.body = NULL;
06428 rle.isCometTail = false;
06429
06430
06431
06432
06433 float scale = astro::lightYearsToKilometers(1.0f);
06434 rle.position = Point3f(relPos.x * scale, relPos.y * scale, relPos.z * scale);
06435 rle.distance = rle.position.distanceFromOrigin();
06436 rle.radius = star.getRadius();
06437 rle.discSizeInPixels = discSizeInPixels;
06438 rle.appMag = appMag;
06439 renderList->insert(renderList->end(), rle);
06440 }
06441 }
06442 }
06443
06444
06445 void Renderer::renderStars(const StarDatabase& starDB,
06446 float faintestMagNight,
06447 const Observer& observer)
06448 {
06449 StarRenderer starRenderer;
06450 Point3f obsPos = (Point3f) observer.getPosition();
06451 obsPos.x *= 1e-6f;
06452 obsPos.y *= 1e-6f;
06453 obsPos.z *= 1e-6f;
06454
06455 starRenderer.context = context;
06456 starRenderer.observer = &observer;
06457 starRenderer.obsPos = obsPos;
06458 starRenderer.viewNormal = Vec3f(0, 0, -1) * observer.getOrientation().toMatrix3();
06459 starRenderer.glareParticles = &glareParticles;
06460 starRenderer.renderList = &renderList;
06461 starRenderer.starVertexBuffer = starVertexBuffer;
06462 starRenderer.fov = fov;
06463
06464
06465 starRenderer.size = pixelSize * 1.6f / corrFac;
06466 starRenderer.pixelSize = pixelSize;
06467 starRenderer.brightnessScale = brightnessScale * corrFac;
06468 starRenderer.brightnessBias = brightnessBias;
06469 starRenderer.faintestMag = faintestMag;
06470 starRenderer.faintestMagNight = faintestMagNight;
06471 starRenderer.saturationMag = saturationMag;
06472 starRenderer.distanceLimit = distanceLimit;
06473
06474 if (starStyle == ScaledDiscStars)
06475 {
06476 starRenderer.useDiscs = true;
06477 starRenderer.brightnessScale *= 2.0f;
06478 starRenderer.maxDiscSize = starRenderer.size * MaxScaledDiscStarSize;
06479 }
06480
06481 starRenderer.colorTemp = colorTemp;
06482
06483 glareParticles.clear();
06484
06485 starVertexBuffer->setBillboardOrientation(observer.getOrientation());
06486
06487 glEnable(GL_TEXTURE_2D);
06488
06489 starTex->bind();
06490 starRenderer.starVertexBuffer->start(starStyle == PointStars);
06491 starDB.findVisibleStars(starRenderer,
06492 obsPos,
06493 observer.getOrientation(),
06494