render.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:390k
- width, height, 0);
- glBegin(GL_QUADS);
- drawBlendedVertices(0.0f, -ydelta, 0.632f);
- drawBlendedVertices(0.0f, ydelta, 0.632f);
- drawBlendedVertices(0.0f, -2.0f*ydelta, 0.159f);
- drawBlendedVertices(0.0f, 2.0f*ydelta, 0.159f);
- drawBlendedVertices(0.0f, -3.0f*ydelta, 0.016f);
- drawBlendedVertices(0.0f, 3.0f*ydelta, 0.016f);
- glEnd();
- #ifdef USE_BLOOM_LISTS
- glEndList();
- }
- glCallList(gaussianLists[2]);
- #endif
- }
- void Renderer::drawBlur()
- {
- blurTextures[0]->bind();
- glBegin(GL_QUADS);
- drawBlendedVertices(0.0f, 0.0f, 1.0f);
- glEnd();
- blurTextures[1]->bind();
- glBegin(GL_QUADS);
- drawBlendedVertices(0.0f, 0.0f, 1.0f);
- glEnd();
- }
- bool Renderer::getBloomEnabled()
- {
- return bloomEnabled;
- }
- void Renderer::setBloomEnabled(bool aBloomEnabled)
- {
- bloomEnabled = aBloomEnabled;
- }
- void Renderer::increaseBrightness()
- {
- brightPlus += 1.0f;
- }
- void Renderer::decreaseBrightness()
- {
- brightPlus -= 1.0f;
- }
- float Renderer::getBrightness()
- {
- return brightPlus;
- }
- #endif // USE_HDR
- void Renderer::render(const Observer& observer,
- const Universe& universe,
- float faintestMagNight,
- const Selection& sel)
- {
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- #ifdef USE_HDR
- renderToTexture(observer, universe, faintestMagNight, sel);
- //------------- Post processing from here ------------//
- glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT);
- glEnable(GL_TEXTURE_2D);
- glDisable(GL_BLEND);
- glDisable(GL_LIGHTING);
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0 );
- glMatrixMode (GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- if (bloomEnabled)
- {
- renderToBlurTexture(0);
- renderToBlurTexture(1);
- // renderToBlurTexture(2);
- }
- drawSceneTexture();
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- #ifdef HDR_COMPRESS
- // Assume luminance 1.0 mapped to 128 previously
- // Compositing a 2nd copy doubles 128->255
- drawSceneTexture();
- #endif
- if (bloomEnabled)
- {
- drawBlur();
- }
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- glPopAttrib();
- #else
- draw(observer, universe, faintestMagNight, sel);
- #endif
- }
- void Renderer::draw(const Observer& observer,
- const Universe& universe,
- float faintestMagNight,
- const Selection& sel)
- {
- // Get the observer's time
- double now = observer.getTime();
- realTime = observer.getRealTime();
- frameCount++;
- settingsChanged = false;
- // Compute the size of a pixel
- setFieldOfView(radToDeg(observer.getFOV()));
- pixelSize = calcPixelSize(fov, (float) windowHeight);
- // Set up the projection we'll use for rendering stars.
- gluPerspective(fov,
- (float) windowWidth / (float) windowHeight,
- NEAR_DIST, FAR_DIST);
- // Set the modelview matrix
- glMatrixMode(GL_MODELVIEW);
- // Get the displayed surface texture set to use from the observer
- displayedSurface = observer.getDisplayedSurface();
- locationFilter = observer.getLocationFilter();
- if (usePointSprite && getGLContext()->getVertexProcessor() != NULL)
- {
- useNewStarRendering = true;
- }
- else
- {
- useNewStarRendering = false;
- }
- // Highlight the selected object
- highlightObject = sel;
- m_cameraOrientation = observer.getOrientationf();
- // Get the view frustum used for culling in camera space.
- float viewAspectRatio = (float) windowWidth / (float) windowHeight;
- Frustum frustum(degToRad(fov),
- viewAspectRatio,
- MinNearPlaneDistance);
- // Get the transformed frustum, used for culling in the astrocentric coordinate
- // system.
- Frustum xfrustum(degToRad(fov),
- viewAspectRatio,
- MinNearPlaneDistance);
- xfrustum.transform(conjugate(observer.getOrientationf()).toMatrix3());
- // Set up the camera for star rendering; the units of this phase
- // are light years.
- Point3f observerPosLY = (Point3f) observer.getPosition();
- observerPosLY.x *= 1e-6f;
- observerPosLY.y *= 1e-6f;
- observerPosLY.z *= 1e-6f;
- glPushMatrix();
- glRotate(m_cameraOrientation);
- // Get the model matrix *before* translation. We'll use this for
- // positioning star and planet labels.
- glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
- glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
- clearSortedAnnotations();
- // Put all solar system bodies into the render list. Stars close and
- // large enough to have discernible surface detail are also placed in
- // renderList.
- renderList.clear();
- orbitPathList.clear();
- lightSourceList.clear();
- secondaryIlluminators.clear();
- // See if we want to use AutoMag.
- if ((renderFlags & ShowAutoMag) != 0)
- {
- autoMag(faintestMag);
- }
- else
- {
- faintestMag = faintestMagNight;
- saturationMag = saturationMagNight;
- }
- faintestPlanetMag = faintestMag;
- #ifdef USE_HDR
- float maxBodyMagPrev = saturationMag;
- maxBodyMag = min(maxBodyMag, saturationMag);
- vector<RenderListEntry>::iterator closestBody;
- const Star *brightestStar = NULL;
- bool foundClosestBody = false;
- bool foundBrightestStar = false;
- #endif
- if (renderFlags & ShowPlanets)
- {
- nearStars.clear();
- universe.getNearStars(observer.getPosition(), 1.0f, nearStars);
- // Set up direct light sources (i.e. just stars at the moment)
- setupLightSources(nearStars, observer.getPosition(), now, lightSourceList);
- // Traverse the frame trees of each nearby solar system and
- // build the list of objects to be rendered.
- for (vector<const Star*>::const_iterator iter = nearStars.begin();
- iter != nearStars.end(); iter++)
- {
- const Star* sun = *iter;
- SolarSystem* solarSystem = universe.getSolarSystem(sun);
- if (solarSystem != NULL)
- {
- FrameTree* solarSysTree = solarSystem->getFrameTree();
- if (solarSysTree != NULL)
- {
- if (solarSysTree->updateRequired())
- {
- // Tree has changed, so we must recompute bounding spheres.
- solarSysTree->recomputeBoundingSphere();
- solarSysTree->markUpdated();
- }
- // Compute the position of the observer in astrocentric coordinates
- Point3d astrocentricObserverPos = astrocentricPosition(observer.getPosition(), *sun, now);
- // Build render lists for bodies and orbits paths
- buildRenderLists(astrocentricObserverPos,
- xfrustum,
- Vec3d(0.0, 0.0, -1.0) * observer.getOrientation().toMatrix3(),
- Vec3d(0.0, 0.0, 0.0),
- solarSysTree,
- observer,
- now);
- if (renderFlags & ShowOrbits)
- {
- buildOrbitLists(astrocentricObserverPos,
- observer.getOrientationf(),
- xfrustum,
- solarSysTree,
- now);
- }
- }
- }
- addStarOrbitToRenderList(*sun, observer, now);
- }
- if ((labelMode & (BodyLabelMask)) != 0)
- {
- buildLabelLists(xfrustum, now);
- }
- starTex->bind();
- }
- setupSecondaryLightSources(secondaryIlluminators, lightSourceList);
- #ifdef USE_HDR
- Mat3f viewMat = conjugate(observer.getOrientationf()).toMatrix3();
- float maxSpan = (float) sqrt(square((float) windowWidth) +
- square((float) windowHeight));
- float nearZcoeff = (float) cos(degToRad(fov / 2)) *
- ((float) windowHeight / maxSpan);
- // Remove objects from the render list that lie completely outside the
- // view frustum.
- vector<RenderListEntry>::iterator notCulled = renderList.begin();
- for (vector<RenderListEntry>::iterator iter = renderList.begin();
- iter != renderList.end(); iter++)
- {
- Point3f center = iter->position * viewMat;
- bool convex = true;
- float radius = 1.0f;
- float cullRadius = 1.0f;
- float cloudHeight = 0.0f;
- switch (iter->renderableType)
- {
- case RenderListEntry::RenderableStar:
- continue;
- case RenderListEntry::RenderableCometTail:
- radius = iter->radius;
- cullRadius = radius;
- convex = false;
- break;
- case RenderListEntry::RenderableReferenceMark:
- radius = iter->radius;
- cullRadius = radius;
- convex = false;
- break;
- case RenderListEntry::RenderableBody:
- default:
- radius = iter->body->getBoundingRadius();
- if (iter->body->getRings() != NULL)
- {
- radius = iter->body->getRings()->outerRadius;
- convex = false;
- }
- if (!iter->body->isEllipsoid())
- convex = false;
- cullRadius = radius;
- if (iter->body->getAtmosphere() != NULL)
- {
- cullRadius += iter->body->getAtmosphere()->height;
- cloudHeight = max(iter->body->getAtmosphere()->cloudHeight,
- iter->body->getAtmosphere()->mieScaleHeight * (float) -log(AtmosphereExtinctionThreshold));
- }
- break;
- }
- // Test the object's bounding sphere against the view frustum
- if (frustum.testSphere(center, cullRadius) != Frustum::Outside)
- {
- float nearZ = center.distanceFromOrigin() - radius;
- nearZ = -nearZ * nearZcoeff;
-
- if (nearZ > -MinNearPlaneDistance)
- iter->nearZ = -max(MinNearPlaneDistance, radius / 2000.0f);
- else
- iter->nearZ = nearZ;
-
- if (!convex)
- {
- iter->farZ = center.z - radius;
- if (iter->farZ / iter->nearZ > MaxFarNearRatio * 0.5f)
- iter->nearZ = iter->farZ / (MaxFarNearRatio * 0.5f);
- }
- else
- {
- // Make the far plane as close as possible
- float d = center.distanceFromOrigin();
-
- // Account for ellipsoidal objects
- float eradius = radius;
- if (iter->body != NULL)
- {
- Vec3f semiAxes = iter->body->getSemiAxes();
- float minSemiAxis = min(semiAxes.x, min(semiAxes.y, semiAxes.z));
- eradius *= minSemiAxis / radius;
- }
- if (d > eradius)
- {
- iter->farZ = iter->centerZ - iter->radius;
- }
- else
- {
- // We're inside the bounding sphere (and, if the planet
- // is spherical, inside the planet.)
- iter->farZ = iter->nearZ * 2.0f;
- }
-
- if (cloudHeight > 0.0f)
- {
- // If there's a cloud layer, we need to move the
- // far plane out so that the clouds aren't clipped
- float cloudLayerRadius = eradius + cloudHeight;
- iter->farZ -= (float) sqrt(square(cloudLayerRadius) -
- square(eradius));
- }
- }
-
- *notCulled = *iter;
- notCulled++;
- maxBodyMag = min(maxBodyMag, iter->appMag);
- foundClosestBody = true;
- }
- }
- renderList.resize(notCulled - renderList.begin());
- saturationMag = maxBodyMag;
- #endif // USE_HDR
- Color skyColor(0.0f, 0.0f, 0.0f);
- // Scan through the render list to see if we're inside a planetary
- // atmosphere. If so, we need to adjust the sky color as well as the
- // limiting magnitude of stars (so stars aren't visible in the daytime
- // on planets with thick atmospheres.)
- if ((renderFlags & ShowAtmospheres) != 0)
- {
- for (vector<RenderListEntry>::iterator iter = renderList.begin();
- iter != renderList.end(); iter++)
- {
- if (iter->renderableType == RenderListEntry::RenderableBody && iter->body->getAtmosphere() != NULL)
- {
- // Compute the density of the atmosphere, and from that
- // the amount light scattering. It's complicated by the
- // possibility that the planet is oblate and a simple distance
- // to sphere calculation will not suffice.
- const Atmosphere* atmosphere = iter->body->getAtmosphere();
- float radius = iter->body->getRadius();
- Vec3f semiAxes = iter->body->getSemiAxes() * (1.0f / radius);
- Vec3f recipSemiAxes(1.0f / semiAxes.x,
- 1.0f / semiAxes.y,
- 1.0f / semiAxes.z);
- Mat3f A = Mat3f::scaling(recipSemiAxes);
- Vec3f eyeVec = iter->position - Point3f(0.0f, 0.0f, 0.0f);
- eyeVec *= (1.0f / radius);
- // Compute the orientation of the planet before axial rotation
- Quatd qd = iter->body->getEclipticToEquatorial(now);
- Quatf q((float) qd.w, (float) qd.x, (float) qd.y, (float) qd.z);
- eyeVec = eyeVec * conjugate(q).toMatrix3();
- // ellipDist is not the true distance from the surface unless
- // the planet is spherical. The quantity that we do compute
- // is the distance to the surface along a line from the eye
- // position to the center of the ellipsoid.
- float ellipDist = (float) sqrt((eyeVec * A) * (eyeVec * A)) - 1.0f;
- if (ellipDist < atmosphere->height / radius &&
- atmosphere->height > 0.0f)
- {
- float density = 1.0f - ellipDist /
- (atmosphere->height / radius);
- if (density > 1.0f)
- density = 1.0f;
- Vec3f sunDir = iter->sun;
- Vec3f normal = Point3f(0.0f, 0.0f, 0.0f) - iter->position;
- sunDir.normalize();
- normal.normalize();
- #ifdef USE_HDR
- // Ignore magnitude of planet underneath when lighting atmosphere
- // Could be changed to simulate light pollution, etc
- maxBodyMag = maxBodyMagPrev;
- saturationMag = maxBodyMag;
- #endif
- float illumination = Math<float>::clamp((sunDir * normal) + 0.2f);
- float lightness = illumination * density;
- faintestMag = faintestMag - 15.0f * lightness;
- saturationMag = saturationMag - 15.0f * lightness;
- }
- }
- }
- }
- // Now we need to determine how to scale the brightness of stars. The
- // brightness will be proportional to the apparent magnitude, i.e.
- // a logarithmic function of the stars apparent brightness. This mimics
- // the response of the human eye. We sort of fudge things here and
- // maintain a minimum range of six magnitudes between faintest visible
- // and saturation; this keeps stars from popping in or out as the sun
- // sets or rises.
- #ifdef USE_HDR
- brightnessScale = 1.0f / (faintestMag - saturationMag);
- #else
- if (faintestMag - saturationMag >= 6.0f)
- brightnessScale = 1.0f / (faintestMag - saturationMag);
- else
- brightnessScale = 0.1667f;
- #endif
- #ifdef USE_HDR
- exposurePrev = exposure;
- float exposureNow = 1.f / (1.f+exp((faintestMag - saturationMag + DEFAULT_EXPOSURE)/2.f));
- exposure = exposurePrev + (exposureNow - exposurePrev) * (1.f - exp(-1.f/(15.f * EXPOSURE_HALFLIFE)));
- brightnessScale /= exposure;
- #endif
- #ifdef DEBUG_HDR_TONEMAP
- HDR_LOG <<
- // "brightnessScale = " << brightnessScale <<
- "faint = " << faintestMag << ", " <<
- "sat = " << saturationMag << ", " <<
- "exposure = " << (exposure+brightPlus) << endl;
- #endif
- #ifdef HDR_COMPRESS
- ambientColor = Color(ambientLightLevel*.5f, ambientLightLevel*.5f, ambientLightLevel*.5f);
- #else
- ambientColor = Color(ambientLightLevel, ambientLightLevel, ambientLightLevel);
- #endif
- // Create the ambient light source. For realistic scenes in space, this
- // should be black.
- glAmbientLightColor(ambientColor);
- #ifdef USE_HDR
- glClearColor(skyColor.red(), skyColor.green(), skyColor.blue(), 0.0f);
- #else
- glClearColor(skyColor.red(), skyColor.green(), skyColor.blue(), 1);
- #endif
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glDisable(GL_LIGHTING);
- glDepthMask(GL_FALSE);
- glEnable(GL_BLEND);
- glEnable(GL_TEXTURE_2D);
-
- // Render sky grids first--these will always be in the background
- {
- glDisable(GL_TEXTURE_2D);
- if ((renderFlags & ShowSmoothLines) != 0)
- enableSmoothLines();
- renderSkyGrids(observer);
- if ((renderFlags & ShowSmoothLines) != 0)
- disableSmoothLines();
- glEnable(GL_BLEND);
- glEnable(GL_TEXTURE_2D);
- }
- // Render deep sky objects
- if ((renderFlags & (ShowGalaxies |
- ShowGlobulars |
- ShowNebulae |
- ShowOpenClusters)) != 0 &&
- universe.getDSOCatalog() != NULL)
- {
- renderDeepSkyObjects(universe, observer, faintestMag);
- }
- // Translate the camera before rendering the stars
- glPushMatrix();
- // Render stars
- #ifdef USE_HDR
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
- #endif
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- if ((renderFlags & ShowStars) != 0 && universe.getStarCatalog() != NULL)
- {
- // Disable multisample rendering when drawing point stars
- bool toggleAA = (starStyle == Renderer::PointStars && glIsEnabled(GL_MULTISAMPLE_ARB));
- if (toggleAA)
- glDisable(GL_MULTISAMPLE_ARB);
- if (useNewStarRendering)
- renderPointStars(*universe.getStarCatalog(), faintestMag, observer);
- else
- renderStars(*universe.getStarCatalog(), faintestMag, observer);
- if (toggleAA)
- glEnable(GL_MULTISAMPLE_ARB);
- }
- #ifdef USE_HDR
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- #endif
- glTranslatef(-observerPosLY.x, -observerPosLY.y, -observerPosLY.z);
- // Render asterisms
- if ((renderFlags & ShowDiagrams) != 0 && universe.getAsterisms() != NULL)
- {
- /* We'll linearly fade the lines as a function of the observer's
- distance to the origin of coordinates: */
- float opacity = 1.0f;
- float dist = observerPosLY.distanceFromOrigin() * 1e6f;
- if (dist > MaxAsterismLinesConstDist)
- {
- opacity = clamp((MaxAsterismLinesConstDist - dist) /
- (MaxAsterismLinesDist - MaxAsterismLinesConstDist) + 1);
- }
- glColor(ConstellationColor, opacity);
- glDisable(GL_TEXTURE_2D);
- if ((renderFlags & ShowSmoothLines) != 0)
- enableSmoothLines();
- AsterismList* asterisms = universe.getAsterisms();
- for (AsterismList::const_iterator iter = asterisms->begin();
- iter != asterisms->end(); iter++)
- {
- Asterism* ast = *iter;
- if (ast->getActive())
- {
- if (ast->isColorOverridden())
- glColor(ast->getOverrideColor(), opacity);
- else
- glColor(ConstellationColor, opacity);
- for (int i = 0; i < ast->getChainCount(); i++)
- {
- const Asterism::Chain& chain = ast->getChain(i);
- glBegin(GL_LINE_STRIP);
- for (Asterism::Chain::const_iterator iter = chain.begin();
- iter != chain.end(); iter++)
- glVertex(*iter);
- glEnd();
- }
- }
- }
- if ((renderFlags & ShowSmoothLines) != 0)
- disableSmoothLines();
- }
- if ((renderFlags & ShowBoundaries) != 0)
- {
- /* We'll linearly fade the boundaries as a function of the
- observer's distance to the origin of coordinates: */
- float opacity = 1.0f;
- float dist = observerPosLY.distanceFromOrigin() * 1e6f;
- if (dist > MaxAsterismLabelsConstDist)
- {
- opacity = clamp((MaxAsterismLabelsConstDist - dist) /
- (MaxAsterismLabelsDist - MaxAsterismLabelsConstDist) + 1);
- }
- glColor(BoundaryColor, opacity);
- glDisable(GL_TEXTURE_2D);
- if ((renderFlags & ShowSmoothLines) != 0)
- enableSmoothLines();
- if (universe.getBoundaries() != NULL)
- universe.getBoundaries()->render();
- if ((renderFlags & ShowSmoothLines) != 0)
- disableSmoothLines();
- }
- // Render star and deep sky object labels
- renderBackgroundAnnotations(FontNormal);
- // Render constellations labels
- if ((labelMode & ConstellationLabels) != 0 && universe.getAsterisms() != NULL)
- {
- labelConstellations(*universe.getAsterisms(), observer);
- renderBackgroundAnnotations(FontLarge);
- }
- // Pop observer translation
- glPopMatrix();
- if ((renderFlags & ShowMarkers) != 0)
- {
- renderMarkers(*universe.getMarkers(),
- observer.getPosition(),
- observer.getOrientation(),
- now);
-
- // Render background markers; rendering of other markers is deferred until
- // solar system objects are rendered.
- renderBackgroundAnnotations(FontNormal);
- }
- // Draw the selection cursor
- bool selectionVisible = false;
- if (!sel.empty() && (renderFlags & ShowMarkers))
- {
- UniversalCoord uc = sel.getPosition(now);
- Vec3d offset = (uc - observer.getPosition()) * astro::microLightYearsToKilometers(1.0);
- static MarkerRepresentation cursorRep(MarkerRepresentation::Crosshair);
- selectionVisible = xfrustum.testSphere(Point3d(0, 0, 0) + offset, sel.radius()) != Frustum::Outside;
- if (selectionVisible)
- {
- double distance = offset.length();
- float symbolSize = (float) (sel.radius() / distance) / pixelSize;
- // Modify the marker position so that it is always in front of the marked object.
- double boundingRadius;
- if (sel.body() != NULL)
- boundingRadius = sel.body()->getBoundingRadius();
- else
- boundingRadius = sel.radius();
- offset *= (1.0 - boundingRadius * 1.01 / distance);
- // The selection cursor is only partially visible when the selected object is obscured. To implement
- // this behavior we'll draw two markers at the same position: one that's always visible, and another one
- // that's depth sorted. When the selection is occluded, only the foreground marker is visible. Otherwise,
- // both markers are drawn and cursor appears much brighter as a result.
- if (distance < astro::lightYearsToKilometers(1.0))
- {
- addSortedAnnotation(&cursorRep, EMPTY_STRING, Color(SelectionCursorColor, 1.0f),
- Point3f((float) offset.x, (float) offset.y, (float) offset.z),
- AlignLeft, VerticalAlignTop, symbolSize);
- }
- else
- {
- addAnnotation(backgroundAnnotations, &cursorRep, EMPTY_STRING, Color(SelectionCursorColor, 1.0f),
- Point3f((float) offset.x, (float) offset.y, (float) offset.z),
- AlignLeft, VerticalAlignTop, symbolSize);
- }
- Color occludedCursorColor(SelectionCursorColor.red(), SelectionCursorColor.green() + 0.3f, SelectionCursorColor.blue());
- addAnnotation(foregroundAnnotations,
- &cursorRep, EMPTY_STRING, Color(occludedCursorColor, 0.4f),
- Point3f((float) offset.x, (float) offset.y, (float) offset.z),
- AlignLeft, VerticalAlignTop, symbolSize);
- }
- }
- glPolygonMode(GL_FRONT, (GLenum) renderMode);
- glPolygonMode(GL_BACK, (GLenum) renderMode);
- {
- Mat3f viewMat = conjugate(observer.getOrientationf()).toMatrix3();
- // Remove objects from the render list that lie completely outside the
- // view frustum.
- #ifdef USE_HDR
- maxBodyMag = maxBodyMagPrev;
- float starMaxMag = maxBodyMagPrev;
- notCulled = renderList.begin();
- #else
- vector<RenderListEntry>::iterator notCulled = renderList.begin();
- #endif
- for (vector<RenderListEntry>::iterator iter = renderList.begin();
- iter != renderList.end(); iter++)
- {
- #ifdef USE_HDR
- switch (iter->renderableType)
- {
- case RenderListEntry::RenderableStar:
- break;
- default:
- *notCulled = *iter;
- notCulled++;
- continue;
- }
- #endif
- Point3f center = iter->position * viewMat;
- bool convex = true;
- float radius = 1.0f;
- float cullRadius = 1.0f;
- float cloudHeight = 0.0f;
- #ifndef USE_HDR
- switch (iter->renderableType)
- {
- case RenderListEntry::RenderableStar:
- radius = iter->star->getRadius();
- cullRadius = radius * (1.0f + CoronaHeight);
- break;
- case RenderListEntry::RenderableCometTail:
- radius = iter->radius;
- cullRadius = radius;
- convex = false;
- break;
- case RenderListEntry::RenderableBody:
- radius = iter->body->getBoundingRadius();
- if (iter->body->getRings() != NULL)
- {
- radius = iter->body->getRings()->outerRadius;
- convex = false;
- }
- if (!iter->body->isEllipsoid())
- convex = false;
- cullRadius = radius;
- if (iter->body->getAtmosphere() != NULL)
- {
- cullRadius += iter->body->getAtmosphere()->height;
- cloudHeight = max(iter->body->getAtmosphere()->cloudHeight,
- iter->body->getAtmosphere()->mieScaleHeight * (float) -log(AtmosphereExtinctionThreshold));
- }
- break;
- case RenderListEntry::RenderableReferenceMark:
- radius = iter->radius;
- cullRadius = radius;
- convex = false;
- break;
- default:
- break;
- }
- #else
- radius = iter->star->getRadius();
- cullRadius = radius * (1.0f + CoronaHeight);
- #endif // USE_HDR
- // Test the object's bounding sphere against the view frustum
- if (frustum.testSphere(center, cullRadius) != Frustum::Outside)
- {
- float nearZ = center.distanceFromOrigin() - radius;
- #ifdef USE_HDR
- nearZ = -nearZ * nearZcoeff;
- #else
- float maxSpan = (float) sqrt(square((float) windowWidth) +
- square((float) windowHeight));
- nearZ = -nearZ * (float) cos(degToRad(fov / 2)) *
- ((float) windowHeight / maxSpan);
- #endif
- if (nearZ > -MinNearPlaneDistance)
- iter->nearZ = -max(MinNearPlaneDistance, radius / 2000.0f);
- else
- iter->nearZ = nearZ;
- if (!convex)
- {
- iter->farZ = center.z - radius;
- if (iter->farZ / iter->nearZ > MaxFarNearRatio * 0.5f)
- iter->nearZ = iter->farZ / (MaxFarNearRatio * 0.5f);
- }
- else
- {
- // Make the far plane as close as possible
- float d = center.distanceFromOrigin();
- // Account for ellipsoidal objects
- float eradius = radius;
- if (iter->renderableType == RenderListEntry::RenderableBody)
- {
- Vec3f semiAxes = iter->body->getSemiAxes();
- float minSemiAxis = min(semiAxes.x, min(semiAxes.y, semiAxes.z));
- eradius *= minSemiAxis / radius;
- }
- if (d > eradius)
- {
- iter->farZ = iter->centerZ - iter->radius;
- }
- else
- {
- // We're inside the bounding sphere (and, if the planet
- // is spherical, inside the planet.)
- iter->farZ = iter->nearZ * 2.0f;
- }
- if (cloudHeight > 0.0f)
- {
- // If there's a cloud layer, we need to move the
- // far plane out so that the clouds aren't clipped
- float cloudLayerRadius = eradius + cloudHeight;
- iter->farZ -= (float) sqrt(square(cloudLayerRadius) -
- square(eradius));
- }
- }
- *notCulled = *iter;
- notCulled++;
- #ifdef USE_HDR
- if (iter->discSizeInPixels > 1.0f &&
- iter->appMag < starMaxMag)
- {
- starMaxMag = iter->appMag;
- brightestStar = iter->star;
- foundBrightestStar = true;
- }
- #endif
- }
- }
- renderList.resize(notCulled - renderList.begin());
- // The calls to buildRenderLists/renderStars filled renderList
- // with visible bodies. Sort it front to back, then
- // render each entry in reverse order (TODO: convenient, but not
- // ideal for performance; should render opaque objects front to
- // back, then translucent objects back to front. However, the
- // amount of overdraw in Celestia is typically low.)
- sort(renderList.begin(), renderList.end());
- // Sort the annotations
- sort(depthSortedAnnotations.begin(), depthSortedAnnotations.end());
- // Sort the orbit paths
- sort(orbitPathList.begin(), orbitPathList.end());
- int nEntries = renderList.size();
- #ifdef USE_HDR
- // Compute 1 eclipse between eye - closest body - brightest star
- // This prevents an eclipsed star from increasing exposure
- bool eyeNotEclipsed = true;
- closestBody = renderList.empty() ? renderList.end() : renderList.begin();
- if (foundClosestBody &&
- closestBody != renderList.end() &&
- closestBody->renderableType == RenderListEntry::RenderableBody &&
- closestBody->body && brightestStar)
- {
- const Body *body = closestBody->body;
- double scale = astro::microLightYearsToKilometers(1.0);
- Point3d posBody = body->getAstrocentricPosition(now);
- Point3d posStar;
- Point3d posEye = astrocentricPosition(observer.getPosition(), *brightestStar, now);
- if (body->getSystem() &&
- body->getSystem()->getStar() &&
- body->getSystem()->getStar() != brightestStar)
- {
- UniversalCoord center = body->getSystem()->getStar()->getPosition(now);
- Vec3d v = brightestStar->getPosition(now) - center;
- posStar = Point3d(v.x, v.y, v.z);
- }
- else
- {
- posStar = brightestStar->getPosition(now);
- }
- posStar.x /= scale;
- posStar.y /= scale;
- posStar.z /= scale;
- Vec3d lightToBodyDir = posBody - posStar;
- Vec3d bodyToEyeDir = posEye - posBody;
- if (lightToBodyDir * bodyToEyeDir > 0.0)
- {
- double dist = distance(posEye,
- Ray3d(posBody, lightToBodyDir));
- if (dist < body->getRadius())
- eyeNotEclipsed = false;
- }
- }
- if (eyeNotEclipsed)
- {
- maxBodyMag = min(maxBodyMag, starMaxMag);
- }
- #endif
- // Since we're rendering objects of a huge range of sizes spread over
- // vast distances, we can't just rely on the hardware depth buffer to
- // handle hidden surface removal without a little help. We'll partition
- // the depth buffer into spans that can be rendered without running
- // into terrible depth buffer precision problems. Typically, each body
- // with an apparent size greater than one pixel is allocated its own
- // depth buffer interval. However, this will not correctly handle
- // overlapping objects. If two objects overlap in depth, we must
- // assign them to the same interval.
- depthPartitions.clear();
- int nIntervals = 0;
- float prevNear = -1e12f; // ~ 1 light year
- if (nEntries > 0)
- prevNear = renderList[nEntries - 1].farZ * 1.01f;
- int i;
- // Completely partition the depth buffer. Scan from back to front
- // through all the renderable items that passed the culling test.
- for (i = nEntries - 1; i >= 0; i--)
- {
- // Only consider renderables that will occupy more than one pixel.
- if (renderList[i].discSizeInPixels > 1)
- {
- if (nIntervals == 0 || renderList[i].farZ >= depthPartitions[nIntervals - 1].nearZ)
- {
- // This object spans a depth interval that's disjoint with
- // the current interval, so create a new one for it, and
- // another interval to fill the gap between the last
- // interval.
- DepthBufferPartition partition;
- partition.index = nIntervals;
- partition.nearZ = renderList[i].farZ;
- partition.farZ = prevNear;
- // Omit null intervals
- // TODO: Is this necessary? Shouldn't the >= test prevent this?
- if (partition.nearZ != partition.farZ)
- {
- depthPartitions.push_back(partition);
- nIntervals++;
- }
- partition.index = nIntervals;
- partition.nearZ = renderList[i].nearZ;
- partition.farZ = renderList[i].farZ;
- depthPartitions.push_back(partition);
- nIntervals++;
- prevNear = partition.nearZ;
- }
- else
- {
- // This object overlaps the current span; expand the
- // interval so that it completely contains the object.
- DepthBufferPartition& partition = depthPartitions[nIntervals - 1];
- partition.nearZ = max(partition.nearZ, renderList[i].nearZ);
- partition.farZ = min(partition.farZ, renderList[i].farZ);
- prevNear = partition.nearZ;
- }
- }
- }
- // Scan the list of orbit paths and find the closest one. We'll need
- // adjust the nearest interval to accommodate it.
- float zNearest = prevNear;
- for (i = 0; i < (int) orbitPathList.size(); i++)
- {
- const OrbitPathListEntry& o = orbitPathList[i];
- float minNearDistance = min(-o.radius * 0.0001f, o.centerZ + o.radius);
- if (minNearDistance > zNearest)
- zNearest = minNearDistance;
- }
-
- // Adjust the nearest interval to include the closest marker (if it's
- // closer to the observer than anything else
- if (!depthSortedAnnotations.empty())
- {
- // Factor of 0.999 makes sure ensures that the near plane does not fall
- // exactly at the marker's z coordinate (in which case the marker
- // would be susceptible to being clipped.)
- if (-depthSortedAnnotations[0].position.z > zNearest)
- zNearest = -depthSortedAnnotations[0].position.z * 0.999f;
- }
-
- #if DEBUG_COALESCE
- clog << "nEntries: " << nEntries << ", zNearest: " << zNearest << ", prevNear: " << prevNear << "n";
- #endif
- // If the nearest distance wasn't set, nothing should appear
- // in the frontmost depth buffer interval (so we can set the near plane
- // of the front interval to whatever we want as long as it's less than
- // the far plane distance.
- if (zNearest == prevNear)
- zNearest = 0.0f;
- // Add one last interval for the span from 0 to the front of the
- // nearest object
- {
- // TODO: closest object may not be at entry 0, since objects are
- // sorted by far distance.
- float closest = zNearest;
- if (nEntries > 0)
- {
- closest = max(closest, renderList[0].nearZ);
- // Setting a the near plane distance to zero results in unreliable rendering, even
- // if we don't care about the depth buffer. Compromise and set the near plane
- // distance to a small fraction of distance to the nearest object.
- if (closest == 0.0f)
- {
- closest = renderList[0].nearZ * 0.01f;
- }
- }
- DepthBufferPartition partition;
- partition.index = nIntervals;
- partition.nearZ = closest;
- partition.farZ = prevNear;
- depthPartitions.push_back(partition);
- nIntervals++;
- }
- // If orbits are enabled, adjust the farthest partition so that it
- // can contain the orbit.
- if (!orbitPathList.empty())
- {
- depthPartitions[0].farZ = min(depthPartitions[0].farZ,
- orbitPathList[orbitPathList.size() - 1].centerZ -
- orbitPathList[orbitPathList.size() - 1].radius);
- }
- // We want to avoid overpartitioning the depth buffer. In this stage, we coalesce
- // partitions that have small spans in the depth buffer.
- // TODO: Implement this step!
- vector<Annotation>::iterator annotation = depthSortedAnnotations.begin();
- // Render everything that wasn't culled.
- float intervalSize = 1.0f / (float) max(1, nIntervals);
- i = nEntries - 1;
- for (int interval = 0; interval < nIntervals; interval++)
- {
- currentIntervalIndex = interval;
- beginObjectAnnotations();
- float nearPlaneDistance = -depthPartitions[interval].nearZ;
- float farPlaneDistance = -depthPartitions[interval].farZ;
- // Set the depth range for this interval--each interval is allocated an
- // equal section of the depth buffer.
- glDepthRange(1.0f - (float) (interval + 1) * intervalSize,
- 1.0f - (float) interval * intervalSize);
- // Set up a perspective projection using the current interval's near and
- // far clip planes.
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(fov,
- (float) windowWidth / (float) windowHeight,
- nearPlaneDistance,
- farPlaneDistance);
- glMatrixMode(GL_MODELVIEW);
- Frustum intervalFrustum(degToRad(fov),
- (float) windowWidth / (float) windowHeight,
- -depthPartitions[interval].nearZ,
- -depthPartitions[interval].farZ);
- #if DEBUG_COALESCE
- clog << "interval: " << interval <<
- ", near: " << -depthPartitions[interval].nearZ <<
- ", far: " << -depthPartitions[interval].farZ <<
- "n";
- #endif
- int firstInInterval = i;
- // Render just the opaque objects in the first pass
- while (i >= 0 && renderList[i].farZ < depthPartitions[interval].nearZ)
- {
- // This interval should completely contain the item
- // Unless it's just a point?
- //assert(renderList[i].nearZ <= depthPartitions[interval].near);
- #if DEBUG_COALESCE
- switch (renderList[i].renderableType)
- {
- case RenderListEntry::RenderableBody:
- if (renderList[i].discSizeInPixels > 1)
- {
- clog << renderList[i].body->getName() << "n";
- }
- else
- {
- clog << "point: " << renderList[i].body->getName() << "n";
- }
- break;
-
- case RenderListEntry::RenderableStar:
- if (renderList[i].discSizeInPixels > 1)
- {
- clog << "Starn";
- }
- else
- {
- clog << "point: " << "Star" << "n";
- }
- break;
-
- default:
- break;
- }
- #endif
- // Treat objects that are smaller than one pixel as transparent and render
- // them in the second pass.
- if (renderList[i].isOpaque && renderList[i].discSizeInPixels > 1.0f)
- renderItem(renderList[i], observer, m_cameraOrientation, nearPlaneDistance, farPlaneDistance);
- i--;
- }
- // Render orbit paths
- if (!orbitPathList.empty())
- {
- glDisable(GL_LIGHTING);
- glDisable(GL_TEXTURE_2D);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- #ifdef USE_HDR
- glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
- #else
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- #endif
- if ((renderFlags & ShowSmoothLines) != 0)
- {
- enableSmoothLines();
- }
- // Scan through the list of orbits and render any that overlap this interval
- for (vector<OrbitPathListEntry>::const_iterator orbitIter = orbitPathList.begin();
- orbitIter != orbitPathList.end(); orbitIter++)
- {
- // Test for overlap
- float nearZ = -orbitIter->centerZ - orbitIter->radius;
- float farZ = -orbitIter->centerZ + orbitIter->radius;
- // Don't render orbits when they're completely outside this
- // depth interval. Also, don't render an orbit in this
- // interval if it is vastly larger than the interval
- // range; otherwise, the GPU will have precision troubles
- // when clipping, producing visual artifacts. The factor
- // of 1e5 may need some tuning.
- if (nearZ < farPlaneDistance && farZ > nearPlaneDistance &&
- orbitIter->radius < 1.0e8f * (farPlaneDistance - nearPlaneDistance))
- {
- #ifdef DEBUG_COALESCE
- switch (interval % 6)
- {
- case 0: glColor4f(1.0f, 0.0f, 0.0f, 1.0f); break;
- case 1: glColor4f(1.0f, 1.0f, 0.0f, 1.0f); break;
- case 2: glColor4f(0.0f, 1.0f, 0.0f, 1.0f); break;
- case 3: glColor4f(0.0f, 1.0f, 1.0f, 1.0f); break;
- case 4: glColor4f(0.0f, 0.0f, 1.0f, 1.0f); break;
- case 5: glColor4f(1.0f, 0.0f, 1.0f, 1.0f); break;
- default: glColor4f(1.0f, 1.0f, 1.0f, 1.0f); break;
- }
- #endif
- orbitsRendered++;
- renderOrbit(*orbitIter, now, m_cameraOrientation, intervalFrustum, nearPlaneDistance, farPlaneDistance);
- #if DEBUG_COALESCE
- if (highlightObject.body() == orbitIter->body)
- {
- clog << "orbit, radius=" << orbitIter->radius << "n";
- }
- #endif
- }
- else
- orbitsSkipped++;
- }
- if ((renderFlags & ShowSmoothLines) != 0)
- disableSmoothLines();
- glDepthMask(GL_FALSE);
- }
- // Render transparent objects in the second pass
- i = firstInInterval;
- while (i >= 0 && renderList[i].farZ < depthPartitions[interval].nearZ)
- {
- if (!renderList[i].isOpaque || renderList[i].discSizeInPixels <= 1.0f)
- renderItem(renderList[i], observer, m_cameraOrientation, nearPlaneDistance, farPlaneDistance);
- i--;
- }
- // Render annotations in this interval
- if ((renderFlags & ShowSmoothLines) != 0)
- enableSmoothLines();
- annotation = renderSortedAnnotations(annotation, -depthPartitions[interval].nearZ, -depthPartitions[interval].farZ, FontNormal);
- endObjectAnnotations();
- if ((renderFlags & ShowSmoothLines) != 0)
- disableSmoothLines();
- glDisable(GL_DEPTH_TEST);
- }
- #if 0
- // TODO: Debugging output for new orbit code; remove when development is complete
- clog << "orbits: " << orbitsRendered
- << ", splines: " << splinesRendered
- << ", skipped: " << orbitsSkipped
- << ", sections culled: " << sectionsCulled
- << ", nIntervals: " << nIntervals << "n";
- #endif
- splinesRendered = 0;
- orbitsRendered = 0;
- orbitsSkipped = 0;
- sectionsCulled = 0;
- // reset the depth range
- glDepthRange(0, 1);
- }
-
- renderForegroundAnnotations(FontNormal);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(fov,
- (float) windowWidth / (float) windowHeight,
- NEAR_DIST, FAR_DIST);
- glMatrixMode(GL_MODELVIEW);
- if (!selectionVisible && (renderFlags & ShowMarkers))
- renderSelectionPointer(observer, now, xfrustum, sel);
- // Pop camera orientation matrix
- glPopMatrix();
- glEnable(GL_TEXTURE_2D);
- glDisable(GL_LIGHTING);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glPolygonMode(GL_FRONT, GL_FILL);
- glPolygonMode(GL_BACK, GL_FILL);
-
- glDisable(GL_BLEND);
- glDepthMask(GL_TRUE);
- glEnable(GL_LIGHTING);
- #if 0
- int errCode = glGetError();
- if (errCode != GL_NO_ERROR)
- {
- cout << "glError: " << (char*) gluErrorString(errCode) << 'n';
- }
- #endif
- if (videoSync && glx::glXWaitVideoSyncSGI != NULL)
- {
- unsigned int count;
- glx::glXGetVideoSyncSGI(&count);
- glx::glXWaitVideoSyncSGI(2, (count+1) & 1, &count);
- }
- }
- static void renderRingSystem(float innerRadius,
- float outerRadius,
- float beginAngle,
- float endAngle,
- unsigned int nSections)
- {
- float angle = endAngle - beginAngle;
- glBegin(GL_QUAD_STRIP);
- for (unsigned int i = 0; i <= nSections; i++)
- {
- float t = (float) i / (float) nSections;
- float theta = beginAngle + t * angle;
- float s = (float) sin(theta);
- float c = (float) cos(theta);
- glTexCoord2f(0, 0.5f);
- glVertex3f(c * innerRadius, 0, s * innerRadius);
- glTexCoord2f(1, 0.5f);
- glVertex3f(c * outerRadius, 0, s * outerRadius);
- }
- glEnd();
- }
- // If the an object occupies a pixel or less of screen space, we don't
- // render its mesh at all and just display a starlike point instead.
- // Switching between the particle and mesh renderings of an object is
- // jarring, however . . . so we'll blend in the particle view of the
- // object to smooth things out, making it dimmer as the disc size exceeds the
- // max disc size.
- void Renderer::renderObjectAsPoint_nosprite(Point3f position,
- float radius,
- float appMag,
- float _faintestMag,
- float discSizeInPixels,
- Color color,
- const Quatf& cameraOrientation,
- bool useHalos)
- {
- float maxDiscSize = 1.0f;
- float maxBlendDiscSize = maxDiscSize + 3.0f;
- float discSize = 1.0f;
- if (discSizeInPixels < maxBlendDiscSize || useHalos)
- {
- float fade = 1.0f;
- if (discSizeInPixels > maxDiscSize)
- {
- fade = (maxBlendDiscSize - discSizeInPixels) /
- (maxBlendDiscSize - maxDiscSize - 1.0f);
- if (fade > 1)
- fade = 1;
- }
- #ifdef USE_HDR
- float fieldCorr = 2.0f * FOV/(fov + FOV);
- float satPoint = saturationMagNight * (1.0f + fieldCorr * fieldCorr);
- #else
- float satPoint = saturationMag;
- #endif
- float a = (_faintestMag - appMag) * brightnessScale + brightnessBias;
- if (starStyle == ScaledDiscStars && a > 1.0f)
- discSize = min(discSize * (2.0f * a - 1.0f), maxDiscSize);
- a = clamp(a) * fade;
- // We scale up the particle by a factor of 1.6 (at fov = 45deg)
- // so that it's more visible--the texture we use has fuzzy edges,
- // and if we render it in just one pixel, it's likely to disappear.
- Mat3f m = cameraOrientation.toMatrix3();
- Point3f center = position;
- // Offset the glare sprite so that it lies in front of the object
- Vec3f direction(center.x, center.y, center.z);
- direction.normalize();
- // Position the sprite on the the line between the viewer and the
- // object, and on a plane normal to the view direction.
- center = center + direction * (radius / ((Vec3f(0, 0, 1.0f) * m) * direction));
- float centerZ = (center * m.transpose()).z;
- float size = discSize * pixelSize * 1.6f * centerZ / corrFac;
- Vec3f v0 = Vec3f(-1, -1, 0) * m;
- Vec3f v1 = Vec3f( 1, -1, 0) * m;
- Vec3f v2 = Vec3f( 1, 1, 0) * m;
- Vec3f v3 = Vec3f(-1, 1, 0) * m;
- glEnable(GL_DEPTH_TEST);
- starTex->bind();
- glColor(color, a);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 1);
- glVertex(center + (v0 * size));
- glTexCoord2f(1, 1);
- glVertex(center + (v1 * size));
- glTexCoord2f(1, 0);
- glVertex(center + (v2 * size));
- glTexCoord2f(0, 0);
- glVertex(center + (v3 * size));
- glEnd();
- // If the object is brighter than magnitude 1, add a halo around it to
- // make it appear more brilliant. This is a hack to compensate for the
- // limited dynamic range of monitors.
- if (useHalos && appMag < satPoint)
- {
- float dist = center.distanceFromOrigin();
- float s = dist * 0.001f * (3 - (appMag - satPoint)) * 2;
- if (s > size * 3)
- size = s * 2.0f/(1.0f + FOV/fov);
- else
- size = size * 3;
- float realSize = discSizeInPixels * pixelSize * dist;
- if (size < realSize * 6)
- size = realSize * 6;
- a = GlareOpacity * clamp((appMag - satPoint) * -0.8f);
- gaussianGlareTex->bind();
- glColor(color, a);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 1);
- glVertex(center + (v0 * size));
- glTexCoord2f(1, 1);
- glVertex(center + (v1 * size));
- glTexCoord2f(1, 0);
- glVertex(center + (v2 * size));
- glTexCoord2f(0, 0);
- glVertex(center + (v3 * size));
- glEnd();
- }
- glDisable(GL_DEPTH_TEST);
- }
- }
- // If the an object occupies a pixel or less of screen space, we don't
- // render its mesh at all and just display a starlike point instead.
- // Switching between the particle and mesh renderings of an object is
- // jarring, however . . . so we'll blend in the particle view of the
- // object to smooth things out, making it dimmer as the disc size exceeds the
- // max disc size.
- void Renderer::renderObjectAsPoint(Point3f position,
- float radius,
- float appMag,
- float _faintestMag,
- float discSizeInPixels,
- Color color,
- const Quatf& cameraOrientation,
- bool useHalos,
- bool emissive)
- {
- float maxDiscSize = (starStyle == ScaledDiscStars) ? MaxScaledDiscStarSize : 1.0f;
- float maxBlendDiscSize = maxDiscSize + 3.0f;
- bool useScaledDiscs = starStyle == ScaledDiscStars;
- if (discSizeInPixels < maxBlendDiscSize || useHalos)
- {
- float alpha = 1.0f;
- float fade = 1.0f;
- float size = BaseStarDiscSize;
- #ifdef USE_HDR
- float fieldCorr = 2.0f * FOV/(fov + FOV);
- float satPoint = saturationMagNight * (1.0f + fieldCorr * fieldCorr);
- satPoint += brightPlus;
- #else
- float satPoint = _faintestMag - (1.0f - brightnessBias) / brightnessScale;
- #endif
- if (discSizeInPixels > maxDiscSize)
- {
- fade = (maxBlendDiscSize - discSizeInPixels) /
- (maxBlendDiscSize - maxDiscSize);
- if (fade > 1)
- fade = 1;
- }
- alpha = (_faintestMag - appMag) * brightnessScale * 2.0f + brightnessBias;
- float pointSize = size;
- float glareSize = 0.0f;
- float glareAlpha = 0.0f;
- if (useScaledDiscs)
- {
- if (alpha < 0.0f)
- {
- alpha = 0.0f;
- }
- else if (alpha > 1.0f)
- {
- float discScale = min(MaxScaledDiscStarSize, (float) pow(2.0f, 0.3f * (satPoint - appMag)));
- pointSize *= max(1.0f, discScale);
- glareAlpha = min(0.5f, discScale / 4.0f);
- if (discSizeInPixels > MaxScaledDiscStarSize)
- {
- glareAlpha = min(glareAlpha,
- (MaxScaledDiscStarSize - discSizeInPixels) / MaxScaledDiscStarSize + 1.0f);
- }
- glareSize = pointSize * 3.0f;
- alpha = 1.0f;
- }
- }
- else
- {
- if (alpha < 0.0f)
- {
- alpha = 0.0f;
- }
- else if (alpha > 1.0f)
- {
- float discScale = min(100.0f, satPoint - appMag + 2.0f);
- glareAlpha = min(GlareOpacity, (discScale - 2.0f) / 4.0f);
- glareSize = pointSize * discScale * 2.0f ;
- if (emissive)
- glareSize = max(glareSize, pointSize * discSizeInPixels * 3.0f);
- }
- }
- alpha *= fade;
- if (!emissive)
- {
- glareSize = max(glareSize, pointSize * discSizeInPixels * 3.0f);
- glareAlpha *= fade;
- }
- Mat3f m = cameraOrientation.toMatrix3();
- Point3f center = position;
- // Offset the glare sprite so that it lies in front of the object
- Vec3f direction(center.x, center.y, center.z);
- direction.normalize();
- // Position the sprite on the the line between the viewer and the
- // object, and on a plane normal to the view direction.
- center = center + direction * (radius / ((Vec3f(0, 0, 1.0f) * m) * direction));
- glEnable(GL_DEPTH_TEST);
- #if !defined(NO_MAX_POINT_SIZE)
- // TODO: OpenGL appears to limit the max point size unless we
- // actually set up a shader that writes the pointsize values. To get
- // around this, we'll use billboards.
- Vec3f v0 = Vec3f(-1, -1, 0) * m;
- Vec3f v1 = Vec3f( 1, -1, 0) * m;
- Vec3f v2 = Vec3f( 1, 1, 0) * m;
- Vec3f v3 = Vec3f(-1, 1, 0) * m;
- float distanceAdjust = pixelSize * center.distanceFromOrigin() * 0.5f;
- if (starStyle == PointStars)
- {
- glDisable(GL_TEXTURE_2D);
- glBegin(GL_POINTS);
- glColor(color, alpha);
- glVertex(center);
- glEnd();
- glEnable(GL_TEXTURE_2D);
- }
- else
- {
- gaussianDiscTex->bind();
- pointSize *= distanceAdjust;
- glBegin(GL_QUADS);
- glColor(color, alpha);
- glTexCoord2f(0, 1);
- glVertex(center + (v0 * pointSize));
- glTexCoord2f(1, 1);
- glVertex(center + (v1 * pointSize));
- glTexCoord2f(1, 0);
- glVertex(center + (v2 * pointSize));
- glTexCoord2f(0, 0);
- glVertex(center + (v3 * pointSize));
- glEnd();
- }
- // If the object is brighter than magnitude 1, add a halo around it to
- // make it appear more brilliant. This is a hack to compensate for the
- // limited dynamic range of monitors.
- //
- // TODO: Stars look fine but planets look unrealistically bright
- // with halos.
- if (useHalos && glareAlpha > 0.0f)
- {
- gaussianGlareTex->bind();
- glareSize *= distanceAdjust;
- glBegin(GL_QUADS);
- glColor(color, glareAlpha);
- glTexCoord2f(0, 1);
- glVertex(center + (v0 * glareSize));
- glTexCoord2f(1, 1);
- glVertex(center + (v1 * glareSize));
- glTexCoord2f(1, 0);
- glVertex(center + (v2 * glareSize));
- glTexCoord2f(0, 0);
- glVertex(center + (v3 * glareSize));
- glEnd();
- }
- #else
- // Disabled because of point size limits
- glEnable(GL_POINT_SPRITE_ARB);
- glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
- gaussianDiscTex->bind();
- glColor(color, alpha);
- glPointSize(pointSize);
- glBegin(GL_POINTS);
- glVertex(center);
- glEnd();
- // If the object is brighter than magnitude 1, add a halo around it to
- // make it appear more brilliant. This is a hack to compensate for the
- // limited dynamic range of monitors.
- //
- // TODO: Stars look fine but planets look unrealistically bright
- // with halos.
- if (useHalos && glareAlpha > 0.0f)
- {
- gaussianGlareTex->bind();
- glColor(color, glareAlpha);
- glPointSize(glareSize);
- glBegin(GL_POINTS);
- glVertex(center);
- glEnd();
- }
- glDisable(GL_POINT_SPRITE_ARB);
- glDisable(GL_DEPTH_TEST);
- #endif // NO_MAX_POINT_SIZE
- }
- }
- static void renderBumpMappedMesh(const GLContext& context,
- Texture& baseTexture,
- Texture& bumpTexture,
- Vec3f lightDirection,
- Quatf orientation,
- Color ambientColor,
- const Frustum& frustum,
- float lod)
- {
- // We're doing our own per-pixel lighting, so disable GL's lighting
- glDisable(GL_LIGHTING);
- // Render the base texture on the first pass . . . The color
- // should have already been set up by the caller.
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, lod,
- &baseTexture);
- // The 'default' light vector for the bump map is (0, 0, 1). Determine
- // a rotation transformation that will move the sun direction to
- // this vector.
- Quatf lightOrientation = Quatf::vecToVecRotation(Vec3f(0.0f, 0.0f, 1.0f), lightDirection);
- glEnable(GL_BLEND);
- glBlendFunc(GL_DST_COLOR, GL_ZERO);
- // Set up the bump map with one directional light source
- SetupCombinersBumpMap(bumpTexture, *normalizationTex, ambientColor);
- // The second set texture coordinates will contain the light
- // direction in tangent space. We'll generate the texture coordinates
- // from the surface normals using GL_NORMAL_MAP_EXT and then
- // use the texture matrix to rotate them into tangent space.
- // This method of generating tangent space light direction vectors
- // isn't as general as transforming the light direction by an
- // orthonormal basis for each mesh vertex, but it works well enough
- // for spheres illuminated by directional light sources.
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);
- // Set up GL_NORMAL_MAP_EXT texture coordinate generation. This
- // mode is part of the cube map extension.
- glEnable(GL_TEXTURE_GEN_R);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
- glEnable(GL_TEXTURE_GEN_S);
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
- glEnable(GL_TEXTURE_GEN_T);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
- // Set up the texture transformation--the light direction and the
- // viewer orientation both need to be considered.
- glMatrixMode(GL_TEXTURE);
- glScalef(-1.0f, 1.0f, 1.0f);
- glRotate(lightOrientation * ~orientation);
- glMatrixMode(GL_MODELVIEW);
- glx::glActiveTextureARB(GL_TEXTURE0_ARB);
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, lod,
- &bumpTexture);
- // Reset the second texture unit
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glDisable(GL_TEXTURE_GEN_R);
- glDisable(GL_TEXTURE_GEN_S);
- glDisable(GL_TEXTURE_GEN_T);
- DisableCombiners();
- glDisable(GL_BLEND);
- }
- static void renderSmoothMesh(const GLContext& context,
- Texture& baseTexture,
- Vec3f lightDirection,
- Quatf orientation,
- Color ambientColor,
- float lod,
- const Frustum& frustum,
- bool invert = false)
- {
- Texture* textures[4];
- // We're doing our own per-pixel lighting, so disable GL's lighting
- glDisable(GL_LIGHTING);
- // The 'default' light vector for the bump map is (0, 0, 1). Determine
- // a rotation transformation that will move the sun direction to
- // this vector.
- Quatf lightOrientation = Quatf::vecToVecRotation(Vec3f(0.0f, 0.0f, 1.0f), lightDirection);
- SetupCombinersSmooth(baseTexture, *normalizationTex, ambientColor, invert);
- // The second set texture coordinates will contain the light
- // direction in tangent space. We'll generate the texture coordinates
- // from the surface normals using GL_NORMAL_MAP_EXT and then
- // use the texture matrix to rotate them into tangent space.
- // This method of generating tangent space light direction vectors
- // isn't as general as transforming the light direction by an
- // orthonormal basis for each mesh vertex, but it works well enough
- // for spheres illuminated by directional light sources.
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);
- // Set up GL_NORMAL_MAP_EXT texture coordinate generation. This
- // mode is part of the cube map extension.
- glEnable(GL_TEXTURE_GEN_R);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
- glEnable(GL_TEXTURE_GEN_S);
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
- glEnable(GL_TEXTURE_GEN_T);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB);
- // Set up the texture transformation--the light direction and the
- // viewer orientation both need to be considered.
- glMatrixMode(GL_TEXTURE);
- glRotate(lightOrientation * ~orientation);
- glMatrixMode(GL_MODELVIEW);
- glx::glActiveTextureARB(GL_TEXTURE0_ARB);
- textures[0] = &baseTexture;
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, lod,
- textures, 1);
- // Reset the second texture unit
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glDisable(GL_TEXTURE_GEN_R);
- glDisable(GL_TEXTURE_GEN_S);
- glDisable(GL_TEXTURE_GEN_T);
- DisableCombiners();
- }
- // Used to sort light sources in order of decreasing irradiance
- struct LightIrradiancePredicate
- {
- int unused;
- LightIrradiancePredicate() {};
- bool operator()(const DirectionalLight& l0,
- const DirectionalLight& l1) const
- {
- return (l0.irradiance > l1.irradiance);
- }
- };
- void renderAtmosphere(const Atmosphere& atmosphere,
- Point3f center,
- float radius,
- const Vec3f& sunDirection,
- Color ambientColor,
- float fade,
- bool lit)
- {
- if (atmosphere.height == 0.0f)
- return;
- glDepthMask(GL_FALSE);
- Vec3f eyeVec = center - Point3f(0.0f, 0.0f, 0.0f);
- double centerDist = eyeVec.length();
- // double surfaceDist = (double) centerDist - (double) radius;
- Vec3f normal = eyeVec;
- normal = normal / (float) centerDist;
- float tangentLength = (float) sqrt(square(centerDist) - square(radius));
- float atmRadius = tangentLength * radius / (float) centerDist;
- float atmOffsetFromCenter = square(radius) / (float) centerDist;
- Point3f atmCenter = center - atmOffsetFromCenter * normal;
- Vec3f uAxis, vAxis;
- if (abs(normal.x) < abs(normal.y) && abs(normal.x) < abs(normal.z))
- {
- uAxis = Vec3f(1, 0, 0) ^ normal;
- uAxis.normalize();
- }
- else if (abs(eyeVec.y) < abs(normal.z))
- {
- uAxis = Vec3f(0, 1, 0) ^ normal;
- uAxis.normalize();
- }
- else
- {
- uAxis = Vec3f(0, 0, 1) ^ normal;
- uAxis.normalize();
- }
- vAxis = uAxis ^ normal;
- float height = atmosphere.height / radius;
- glBegin(GL_QUAD_STRIP);
- int divisions = 180;
- for (int i = 0; i <= divisions; i++)
- {
- float theta = (float) i / (float) divisions * 2 * (float) PI;
- Vec3f v = (float) cos(theta) * uAxis + (float) sin(theta) * vAxis;
- Point3f base = atmCenter + v * atmRadius;
- Vec3f toCenter = base - center;
- float cosSunAngle = (toCenter * sunDirection) / radius;
- float brightness = 1.0f;
- float botColor[3];
- float topColor[3];
- botColor[0] = atmosphere.lowerColor.red();
- botColor[1] = atmosphere.lowerColor.green();
- botColor[2] = atmosphere.lowerColor.blue();
- topColor[0] = atmosphere.upperColor.red();
- topColor[1] = atmosphere.upperColor.green();
- topColor[2] = atmosphere.upperColor.blue();
- if (cosSunAngle < 0.2f && lit)
- {
- if (cosSunAngle < -0.2f)
- {
- brightness = 0;
- }
- else
- {
- float t = (0.2f + cosSunAngle) * 2.5f;
- brightness = t;
- botColor[0] = Mathf::lerp(t, 1.0f, botColor[0]);
- botColor[1] = Mathf::lerp(t, 0.3f, botColor[1]);
- botColor[2] = Mathf::lerp(t, 0.0f, botColor[2]);
- topColor[0] = Mathf::lerp(t, 1.0f, topColor[0]);
- topColor[1] = Mathf::lerp(t, 0.3f, topColor[1]);
- topColor[2] = Mathf::lerp(t, 0.0f, topColor[2]);
- }
- }
- glColor4f(botColor[0], botColor[1], botColor[2],
- 0.85f * fade * brightness + ambientColor.red());
- glVertex(base - toCenter * height * 0.05f);
- glColor4f(topColor[0], topColor[1], topColor[2], 0.0f);
- glVertex(base + toCenter * height);
- }
- glEnd();
- }
- static Vec3f ellipsoidTangent(const Vec3f& recipSemiAxes,
- const Vec3f& w,
- const Vec3f& e,
- const Vec3f& e_,
- float ee)
- {
- // We want to find t such that -E(1-t) + Wt is the direction of a ray
- // tangent to the ellipsoid. A tangent ray will intersect the ellipsoid
- // at exactly one point. Finding the intersection between a ray and an
- // ellipsoid ultimately requires using the quadratic formula, which has
- // one solution when the discriminant (b^2 - 4ac) is zero. The code below
- // computes the value of t that results in a discriminant of zero.
- Vec3f w_(w.x * recipSemiAxes.x, w.y * recipSemiAxes.y, w.z * recipSemiAxes.z);
- float ww = w_ * w_;
- float ew = w_ * e_;
- // Before elimination of terms:
- // float a = 4 * square(ee + ew) - 4 * (ee + 2 * ew + ww) * (ee - 1.0f);
- // float b = -8 * ee * (ee + ew) - 4 * (-2 * (ee + ew) * (ee - 1.0f));
- // float c = 4 * ee * ee - 4 * (ee * (ee - 1.0f));
- // Simplify the below expression and eliminate the ee^2 terms; this
- // prevents precision errors, as ee tends to be a very large value.
- //T a = 4 * square(ee + ew) - 4 * (ee + 2 * ew + ww) * (ee - 1);
- //float a = 4 * square(ee + ew) - 4 * (ee + 2 * ew + ww) * (ee - 1.0f);
- float a = 4 * (square(ew) - ee * ww + ee + 2 * ew + ww);
- float b = -8 * (ee + ew);
- float c = 4 * ee;
- float t = 0.0f;
- float discriminant = b * b - 4 * a * c;
- if (discriminant < 0.0f)
- t = (-b + (float) sqrt(-discriminant)) / (2 * a); // Bad!
- else
- t = (-b + (float) sqrt(discriminant)) / (2 * a);
- // V is the direction vector. We now need the point of intersection,
- // which we obtain by solving the quadratic equation for the ray-ellipse
- // intersection. Since we already know that the discriminant is zero,
- // the solution is just -b/2a
- Vec3f v = -e * (1 - t) + w * t;
- Vec3f v_(v.x * recipSemiAxes.x, v.y * recipSemiAxes.y, v.z * recipSemiAxes.z);
- float a1 = v_ * v_;
- float b1 = 2.0f * v_ * e_;
- float t1 = -b1 / (2 * a1);
- return e + v * t1;
- }
- void Renderer::renderEllipsoidAtmosphere(const Atmosphere& atmosphere,
- Point3f center,
- const Quatf& orientation,
- Vec3f semiAxes,
- const Vec3f& sunDirection,
- const LightingState& ls,
- float pixSize,
- bool lit)
- {
- if (atmosphere.height == 0.0f)
- return;
- glDepthMask(GL_FALSE);
- // Gradually fade in the atmosphere if it's thickness on screen is just
- // over one pixel.
- float fade = clamp(pixSize - 2);
- Mat3f rot = orientation.toMatrix3();
- Mat3f irot = conjugate(orientation).toMatrix3();
- Point3f eyePos(0.0f, 0.0f, 0.0f);
- float radius = max(semiAxes.x, max(semiAxes.y, semiAxes.z));
- Vec3f eyeVec = center - eyePos;
- eyeVec = eyeVec * irot;
- double centerDist = eyeVec.length();
- float height = atmosphere.height / radius;
- Vec3f recipSemiAxes(1.0f / semiAxes.x, 1.0f / semiAxes.y, 1.0f / semiAxes.z);
- Vec3f recipAtmSemiAxes = recipSemiAxes / (1.0f + height);
- Mat3f A = Mat3f::scaling(recipAtmSemiAxes);
- Mat3f A1 = Mat3f::scaling(recipSemiAxes);
- // ellipDist is not the true distance from the surface unless the
- // planet is spherical. Computing the true distance requires finding
- // the roots of a sixth degree polynomial, and isn't actually what we
- // want anyhow since the atmosphere region is just the planet ellipsoid
- // multiplied by a uniform scale factor. The value that we do compute
- // is the distance to the surface along a line from the eye position to
- // the center of the ellipsoid.
- float ellipDist = (float) sqrt((eyeVec * A1) * (eyeVec * A1)) - 1.0f;
- bool within = ellipDist < height;
- // Adjust the tesselation of the sky dome/ring based on distance from the
- // planet surface.
- int nSlices = MaxSkySlices;
- if (ellipDist < 0.25f)
- {
- nSlices = MinSkySlices + max(0, (int) ((ellipDist / 0.25f) * (MaxSkySlices - MinSkySlices)));
- nSlices &= ~1;
- }
- int nRings = min(1 + (int) pixSize / 5, 6);
- int nHorizonRings = nRings;
- if (within)
- nRings += 12;
- float horizonHeight = height;
- if (within)
- {
- if (ellipDist <= 0.0f)
- horizonHeight = 0.0f;
- else
- horizonHeight *= max((float) pow(ellipDist / height, 0.33f), 0.001f);
- }
- Vec3f e = -eyeVec;
- Vec3f e_(e.x * recipSemiAxes.x, e.y * recipSemiAxes.y, e.z * recipSemiAxes.z);
- float ee = e_ * e_;
- // Compute the cosine of the altitude of the sun. This is used to compute
- // the degree of sunset/sunrise coloration.
- float cosSunAltitude = 0.0f;
- {
- // Check for a sun either directly behind or in front of the viewer
- float cosSunAngle = (float) ((sunDirection * e) / centerDist);
- if (cosSunAngle < -1.0f + 1.0e-6f)
- {
- cosSunAltitude = 0.0f;
- }
- else if (cosSunAngle > 1.0f - 1.0e-6f)
- {
- cosSunAltitude = 0.0f;
- }
- else
- {
- Point3f tangentPoint = center +
- ellipsoidTangent(recipSemiAxes,
- (-sunDirection * irot) * (float) centerDist,
- e, e_, ee) * rot;
- Vec3f tangentDir = tangentPoint - eyePos;
- tangentDir.normalize();
- cosSunAltitude = sunDirection * tangentDir;
- }
- }
- Vec3f normal = eyeVec;
- normal = normal / (float) centerDist;
- Vec3f uAxis, vAxis;
- if (abs(normal.x) < abs(normal.y) && abs(normal.x) < abs(normal.z))
- {
- uAxis = Vec3f(1, 0, 0) ^ normal;
- uAxis.normalize();
- }
- else if (abs(eyeVec.y) < abs(normal.z))
- {
- uAxis = Vec3f(0, 1, 0) ^ normal;
- uAxis.normalize();
- }
- else
- {
- uAxis = Vec3f(0, 0, 1) ^ normal;
- uAxis.normalize();
- }
- vAxis = uAxis ^ normal;
- // Compute the contour of the ellipsoid
- int i;
- for (i = 0; i <= nSlices; i++)
- {
- // We want rays with an origin at the eye point and tangent to the the
- // ellipsoid.
- float theta = (float) i / (float) nSlices * 2 * (float) PI;
- Vec3f w = (float) cos(theta) * uAxis + (float) sin(theta) * vAxis;
- w = w * (float) centerDist;
- Vec3f toCenter = ellipsoidTangent(recipSemiAxes, w, e, e_, ee);
- skyContour[i].v = toCenter * rot;
- skyContour[i].centerDist = skyContour[i].v.length();
- skyContour[i].eyeDir = skyContour[i].v + (center - eyePos);
- skyContour[i].eyeDist = skyContour[i].eyeDir.length();
- skyContour[i].eyeDir.normalize();
- float skyCapDist = (float) sqrt(square(skyContour[i].eyeDist) +
- square(horizonHeight * radius));
- skyContour[i].cosSkyCapAltitude = skyContour[i].eyeDist /
- skyCapDist;
- }
- Vec3f botColor(atmosphere.lowerColor.red(),
- atmosphere.lowerColor.green(),
- atmosphere.lowerColor.blue());
- Vec3f topColor(atmosphere.upperColor.red(),
- atmosphere.upperColor.green(),
- atmosphere.upperColor.blue());
- Vec3f sunsetColor(atmosphere.sunsetColor.red(),
- atmosphere.sunsetColor.green(),
- atmosphere.sunsetColor.blue());
- if (within)
- {
- Vec3f skyColor(atmosphere.skyColor.red(),
- atmosphere.skyColor.green(),
- atmosphere.skyColor.blue());
- if (ellipDist < 0.0f)
- topColor = skyColor;
- else
- topColor = skyColor + (topColor - skyColor) * (ellipDist / height);
- }
- if (ls.nLights == 0 && lit)
- {
- Vec3f black(0.0f, 0.0f, 0.0f);
- botColor = topColor = sunsetColor = black;
- }
- Vec3f zenith = (skyContour[0].v + skyContour[nSlices / 2].v);
- zenith.normalize();
- zenith *= skyContour[0].centerDist * (1.0f + horizonHeight * 2.0f);
- float minOpacity = within ? (1.0f - ellipDist / height) * 0.75f : 0.0f;
- float sunset = cosSunAltitude < 0.9f ? 0.0f : (cosSunAltitude - 0.9f) * 10.0f;
- // Build the list of vertices
- SkyVertex* vtx = skyVertices;
- for (i = 0; i <= nRings; i++)
- {
- float h = min(1.0f, (float) i / (float) nHorizonRings);
- float hh = (float) sqrt(h);
- float u = i <= nHorizonRings ? 0.0f :
- (float) (i - nHorizonRings) / (float) (nRings - nHorizonRings);
- float r = Mathf::lerp(h, 1.0f - (horizonHeight * 0.05f), 1.0f + horizonHeight);
- float atten = 1.0f - hh;
- for (int j = 0; j < nSlices; j++)
- {
- Vec3f v;
- if (i <= nHorizonRings)
- v = skyContour[j].v * r;
- else
- v = (skyContour[j].v * (1.0f - u) + zenith * u) * r;
- Point3f p = center + v;
- Vec3f viewDir(p.x, p.y, p.z);
- viewDir.normalize();
- float cosSunAngle = viewDir * sunDirection;
- float cosAltitude = viewDir * skyContour[j].eyeDir;
- float brightness = 1.0f;
- float coloration = 0.0f;
- if (lit)
- {
- if (sunset > 0.0f && cosSunAngle > 0.7f && cosAltitude > 0.98f)
- {
- coloration = (1.0f / 0.30f) * (cosSunAngle - 0.70f);
- coloration *= 50.0f * (cosAltitude - 0.98f);
- coloration *= sunset;
- }
- cosSunAngle = (skyContour[j].v * sunDirection) / skyContour[j].centerDist;
- if (cosSunAngle > -0.2f)
- {
- if (cosSunAngle < 0.3f)
- brightness = (cosSunAngle + 0.2f) * 2.0f;
- else
- brightness = 1.0f;
- }
- else
- {
- brightness = 0.0f;
- }
- }
- vtx->x = p.x;
- vtx->y = p.y;
- vtx->z = p.z;
- #if 0
- // Better way of generating sky color gradients--based on
- // altitude angle.
- if (!within)
- {
- hh = (1.0f - cosAltitude) / (1.0f - skyContour[j].cosSkyCapAltitude);
- }
- else
- {
- float top = pow((ellipDist / height), 0.125f) * skyContour[j].cosSkyCapAltitude;
- if (cosAltitude < top)
- hh = 1.0f;
- else
- hh = (1.0f - cosAltitude) / (1.0f - top);
- }
- hh = sqrt(hh);
- //hh = (float) pow(hh, 0.25f);
- #endif
- atten = 1.0f - hh;
- Vec3f color = (1.0f - hh) * botColor + hh * topColor;
- brightness *= minOpacity + (1.0f - minOpacity) * fade * atten;
- if (coloration != 0.0f)
- color = (1.0f - coloration) * color + coloration * sunsetColor;
- #ifdef HDR_COMPRESS
- brightness *= 0.5f;
- #endif
- Color(brightness * color.x,
- brightness * color.y,
- brightness * color.z,
- fade * (minOpacity + (1.0f - minOpacity)) * atten).get(vtx->color);
- vtx++;
- }
- }
- // Create the index list
- int index = 0;
- for (i = 0; i < nRings; i++)
- {
- int baseVertex = i * nSlices;
- for (int j = 0; j < nSlices; j++)
- {
- skyIndices[index++] = baseVertex + j;
- skyIndices[index++] = baseVertex + nSlices + j;
- }
- skyIndices[index++] = baseVertex;
- skyIndices[index++] = baseVertex + nSlices;
- }
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, sizeof(SkyVertex), &skyVertices[0].x);
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SkyVertex),
- static_cast<void*>(&skyVertices[0].color));
- for (i = 0; i < nRings; i++)
- {
- glDrawElements(GL_QUAD_STRIP,
- (nSlices + 1) * 2,
- GL_UNSIGNED_INT,
- &skyIndices[(nSlices + 1) * 2 * i]);
- }
- glDisableClientState(GL_COLOR_ARRAY);
- }
- void renderCompass(Point3f center,
- const Quatf& orientation,
- Vec3f semiAxes,
- float pixelSize)
- {
- Mat3f rot = orientation.toMatrix3();
- Mat3f irot = conjugate(orientation).toMatrix3();
- Point3f eyePos(0.0f, 0.0f, 0.0f);
- float radius = max(semiAxes.x, max(semiAxes.y, semiAxes.z));
- Vec3f eyeVec = center - eyePos;
- eyeVec = eyeVec * irot;
- double centerDist = eyeVec.length();
- float height = 1.0f / radius;
- Vec3f recipSemiAxes(1.0f / semiAxes.x,
- 1.0f / semiAxes.y,
- 1.0f / semiAxes.z);
- Vec3f recipAtmSemiAxes = recipSemiAxes / (1.0f + height);
- Mat3f A = Mat3f::scaling(recipAtmSemiAxes);
- Mat3f A1 = Mat3f::scaling(recipSemiAxes);
- const int nCompassPoints = 16;
- Vec3f compassPoints[nCompassPoints];
- // ellipDist is not the true distance from the surface unless the
- // planet is spherical. Computing the true distance requires finding
- // the roots of a sixth degree polynomial, and isn't actually what we
- // want anyhow since the atmosphere region is just the planet ellipsoid
- // multiplied by a uniform scale factor. The value that we do compute
- // is the distance to the surface along a line from the eye position to
- // the center of the ellipsoid.
- /*float ellipDist = (float) sqrt((eyeVec * A1) * (eyeVec * A1)) - 1.0f; Unused*/
- Vec3f e = -eyeVec;
- Vec3f e_(e.x * recipSemiAxes.x, e.y * recipSemiAxes.y, e.z * recipSemiAxes.z);
- float ee = e_ * e_;
- Vec3f normal = eyeVec;
- normal = normal / (float) centerDist;
- Vec3f uAxis, vAxis;
- Vec3f northPole(0.0f, 1.0f, 0.0f);
- vAxis = normal ^ northPole;
- vAxis.normalize();
- uAxis = vAxis ^ normal;
- // Compute the compass points
- int i;
- for (i = 0; i < nCompassPoints; i++)
- {
- // We want rays with an origin at the eye point and tangent to the the
- // ellipsoid.
- float theta = (float) i / (float) nCompassPoints * 2 * (float) PI;
- Vec3f w = (float) cos(theta) * uAxis + (float) sin(theta) * vAxis;
- w = w * (float) centerDist;
- Vec3f toCenter = ellipsoidTangent(recipSemiAxes, w, e, e_, ee);
- compassPoints[i] = toCenter * rot;
- }
- glColor(compassColor);
- glBegin(GL_LINES);
- glDisable(GL_LIGHTING);
- for (i = 0; i < nCompassPoints; i++)
- {
- float distance = (center + compassPoints[i]).distanceFromOrigin();
- float length = distance * pixelSize * 8.0f;
- if (i % 4 == 0)
- length *= 3.0f;
- else if (i % 2 == 0)
- length *= 2.0f;
- glVertex(center + compassPoints[i]);
- glVertex(center + compassPoints[i] * (1.0f + length));
- }
- glEnd();
- }
- static void setupNightTextureCombine()
- {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_ONE_MINUS_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
- }
- static void setupBumpTexenv()
- {
- // Set up the texenv_combine extension to do DOT3 bump mapping.
- // No support for ambient light yet.
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- // The primary color contains the light direction in surface
- // space, and texture0 is a normal map. The lighting is
- // calculated by computing the dot product.
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_ARB);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- // In the final stage, modulate the lighting value by the
- // base texture color.
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- glEnable(GL_TEXTURE_2D);
- glx::glActiveTextureARB(GL_TEXTURE0_ARB);
- }
- #if 0
- static void setupBumpTexenvAmbient(Color ambientColor)
- {
- float texenvConst[4];
- texenvConst[0] = ambientColor.red();
- texenvConst[1] = ambientColor.green();
- texenvConst[2] = ambientColor.blue();
- texenvConst[3] = ambientColor.alpha();
- // Set up the texenv_combine extension to do DOT3 bump mapping.
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- // The primary color contains the light direction in surface
- // space, and texture0 is a normal map. The lighting is
- // calculated by computing the dot product.
- glx::glActiveTextureARB(GL_TEXTURE0_ARB);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_DOT3_RGB_ARB);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- // Add in the ambient color
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);
- glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, texenvConst);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- glEnable(GL_TEXTURE_2D);
- // In the final stage, modulate the lighting value by the
- // base texture color.
- glx::glActiveTextureARB(GL_TEXTURE2_ARB);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- glEnable(GL_TEXTURE_2D);
- glx::glActiveTextureARB(GL_TEXTURE0_ARB);
- }
- #endif
- static void setupTexenvAmbient(Color ambientColor)
- {
- float texenvConst[4];
- texenvConst[0] = ambientColor.red();
- texenvConst[1] = ambientColor.green();
- texenvConst[2] = ambientColor.blue();
- texenvConst[3] = ambientColor.alpha();
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- // The primary color contains the light direction in surface
- // space, and texture0 is a normal map. The lighting is
- // calculated by computing the dot product.
- glx::glActiveTextureARB(GL_TEXTURE0_ARB);
- glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, texenvConst);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
- glEnable(GL_TEXTURE_2D);
- }
- static void setupTexenvGlossMapAlpha()
- {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_ALPHA);
- }
- static void setLightParameters_VP(VertexProcessor& vproc,
- const LightingState& ls,
- Color materialDiffuse,
- Color materialSpecular)
- {
- Vec3f diffuseColor(materialDiffuse.red(),
- materialDiffuse.green(),
- materialDiffuse.blue());
- #ifdef HDR_COMPRESS
- Vec3f specularColor(materialSpecular.red() * 0.5f,
- materialSpecular.green() * 0.5f,
- materialSpecular.blue() * 0.5f);
- #else
- Vec3f specularColor(materialSpecular.red(),
- materialSpecular.green(),
- materialSpecular.blue());
- #endif
- for (unsigned int i = 0; i < ls.nLights; i++)
- {
- const DirectionalLight& light = ls.lights[i];
- Vec3f lightColor = Vec3f(light.color.red(),
- light.color.green(),
- light.color.blue()) * light.irradiance;
- Vec3f diffuse(diffuseColor.x * lightColor.x,
- diffuseColor.y * lightColor.y,
- diffuseColor.z * lightColor.z);
- Vec3f specular(specularColor.x * lightColor.x,
- specularColor.y * lightColor.y,
- specularColor.z * lightColor.z);
- // Just handle two light sources for now
- if (i == 0)
- {
- vproc.parameter(vp::LightDirection0, ls.lights[0].direction_obj);
- vproc.parameter(vp::DiffuseColor0, diffuse);
- vproc.parameter(vp::SpecularColor0, specular);
- }
- else if (i == 1)
- {
- vproc.parameter(vp::LightDirection1, ls.lights[1].direction_obj);
- vproc.parameter(vp::DiffuseColor1, diffuse);
- vproc.parameter(vp::SpecularColor1, specular);
- }
- }
- }
- static void renderModelDefault(Geometry* geometry,
- const RenderInfo& ri,
- bool lit,
- ResourceHandle texOverride)
- {
- FixedFunctionRenderContext rc;
- Mesh::Material m;
- rc.setLighting(lit);
- if (ri.baseTex == NULL)
- {
- glDisable(GL_TEXTURE_2D);
- }
- else
- {
- glEnable(GL_TEXTURE_2D);
- ri.baseTex->bind();
- }
- glColor(ri.color);
- if (ri.baseTex != NULL)
- {
- m.diffuse = ri.color;
- m.specular = ri.specularColor;
- m.specularPower = ri.specularPower;
- m.maps[Mesh::DiffuseMap] = texOverride;
- rc.setMaterial(&m);
- rc.lock();
- }
- geometry->render(rc);
- if (geometry->usesTextureType(Mesh::EmissiveMap))
- {
- glDisable(GL_LIGHTING);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- rc.setRenderPass(RenderContext::EmissivePass);
- rc.setMaterial(NULL);
- geometry->render(rc);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
- // Reset the material
- float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
- float zero = 0.0f;
- glColor4fv(black);
- glMaterialfv(GL_FRONT, GL_EMISSION, black);
- glMaterialfv(GL_FRONT, GL_SPECULAR, black);
- glMaterialfv(GL_FRONT, GL_SHININESS, &zero);
- }
- static void renderSphereDefault(const RenderInfo& ri,
- const Frustum& frustum,
- bool lit,
- const GLContext& context)
- {
- if (lit)
- glEnable(GL_LIGHTING);
- else
- glDisable(GL_LIGHTING);
- if (ri.baseTex == NULL)
- {
- glDisable(GL_TEXTURE_2D);
- }
- else
- {
- glEnable(GL_TEXTURE_2D);
- ri.baseTex->bind();
- }
- glColor(ri.color);
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, ri.pixWidth,
- ri.baseTex);
- if (ri.nightTex != NULL && ri.useTexEnvCombine)
- {
- ri.nightTex->bind();
- #ifdef USE_HDR
- #ifdef HDR_COMPRESS
- Color nightColor(ri.color.red() * 2.f,
- ri.color.green() * 2.f,
- ri.color.blue() * 2.f,
- ri.nightLightScale); // Modulate brightness using alpha
- #else
- Color nightColor(ri.color.red(),
- ri.color.green(),
- ri.color.blue(),
- ri.nightLightScale); // Modulate brightness using alpha
- #endif
- glColor(nightColor);
- #endif
- setupNightTextureCombine();
- glEnable(GL_BLEND);
- #ifdef USE_HDR
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- #else
- glBlendFunc(GL_ONE, GL_ONE);
- #endif
- glAmbientLightColor(Color::Black); // Disable ambient light
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, ri.pixWidth,
- ri.nightTex);
- glAmbientLightColor(ri.ambientColor);
- #ifdef USE_HDR
- glColor(ri.color);
- #endif
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- }
- if (ri.overlayTex != NULL)
- {
- ri.overlayTex->bind();
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, ri.pixWidth,
- ri.overlayTex);
- glBlendFunc(GL_ONE, GL_ONE);
- }
- }
- // DEPRECATED -- renderSphere_Combiners_VP should be used instead; only
- // very old drivers don't support vertex programs.
- static void renderSphere_Combiners(const RenderInfo& ri,
- const Frustum& frustum,
- const GLContext& context)
- {
- glDisable(GL_LIGHTING);
- if (ri.baseTex == NULL)
- {
- glDisable(GL_TEXTURE_2D);
- }
- else
- {
- glEnable(GL_TEXTURE_2D);
- ri.baseTex->bind();
- }
- glColor(ri.color * ri.sunColor);
- // Don't use a normal map if it's a dxt5nm map--only the GLSL path
- // can handle them.
- if (ri.bumpTex != NULL &&
- (ri.bumpTex->getFormatOptions() & Texture::DXT5NormalMap) == 0)
- {
- renderBumpMappedMesh(context,
- *(ri.baseTex),
- *(ri.bumpTex),
- ri.sunDir_eye,
- ri.orientation,
- ri.ambientColor,
- frustum,
- ri.pixWidth);
- }
- else if (ri.baseTex != NULL)
- {
- renderSmoothMesh(context,
- *(ri.baseTex),
- ri.sunDir_eye,
- ri.orientation,
- ri.ambientColor,
- ri.pixWidth,
- frustum);
- }
- else
- {
- glEnable(GL_LIGHTING);
- g_lodSphere->render(context, frustum, ri.pixWidth, NULL, 0);
- }
- if (ri.nightTex != NULL)
- {
- ri.nightTex->bind();
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- renderSmoothMesh(context,
- *(ri.nightTex),
- ri.sunDir_eye,
- ri.orientation,
- Color::Black,
- ri.pixWidth,
- frustum,
- true);
- }
- if (ri.overlayTex != NULL)
- {
- glEnable(GL_LIGHTING);
- ri.overlayTex->bind();
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::TexCoords0,
- frustum, ri.pixWidth,
- ri.overlayTex);
- #if 0
- renderSmoothMesh(context,
- *(ri.overlayTex),
- ri.sunDir_eye,
- ri.orientation,
- ri.ambientColor,
- ri.pixWidth,
- frustum);
- #endif
- glBlendFunc(GL_ONE, GL_ONE);
- }
- glBlendFunc(GL_SRC_ALPHA, GL_ONE);
- }
- static void renderSphere_DOT3_VP(const RenderInfo& ri,
- const LightingState& ls,
- const Frustum& frustum,
- const GLContext& context)
- {
- VertexProcessor* vproc = context.getVertexProcessor();
- assert(vproc != NULL);
- if (ri.baseTex == NULL)
- {
- glDisable(GL_TEXTURE_2D);
- }
- else
- {
- glEnable(GL_TEXTURE_2D);
- ri.baseTex->bind();
- }
- vproc->enable();
- vproc->parameter(vp::EyePosition, ri.eyePos_obj);
- setLightParameters_VP(*vproc, ls, ri.color, ri.specularColor);
- Color ambient(ri.ambientColor * ri.color);
- #ifdef USE_HDR
- ambient = ri.ambientColor;
- #endif
- vproc->parameter(vp::AmbientColor, ambient);
- vproc->parameter(vp::SpecularExponent, 0.0f, 1.0f, 0.5f, ri.specularPower);
- // Don't use a normal map if it's a dxt5nm map--only the GLSL path
- // can handle them.
- if (ri.bumpTex != NULL &&
- (ri.bumpTex->getFormatOptions() & Texture::DXT5NormalMap) == 0 &&
- ri.baseTex != NULL)
- {
- // We don't yet handle the case where there's a bump map but no
- // base texture.
- #ifdef HDR_COMPRESS
- vproc->use(vp::diffuseBumpHDR);
- #else
- vproc->use(vp::diffuseBump);
- #endif
- if (ri.ambientColor != Color::Black)
- {
- // If there's ambient light, we'll need to render in two passes:
- // one for the ambient light, and the second for light from the star.
- // We could do this in a single pass using three texture stages, but
- // this isn't won't work with hardware that only supported two
- // texture stages.
- // Render the base texture modulated by the ambient color
- setupTexenvAmbient(ambient);
- g_lodSphere->render(context,
- LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
- frustum, ri.pixWidth,
- ri.baseTex);
- // Add the light from the sun
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- setupBumpTexenv();
- g_lodSphere->render(context,
- LODSphereMesh::Normals | LODSphereMesh::Tangents |
- LODSphereMesh::TexCoords0 | LODSphereMesh::VertexProgParams,
- frustum, ri.pixWidth,
- ri.bumpTex, ri.baseTex);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glDisable(GL_BLEND);
- }
- else
- {
- glx::glActiveTextureARB(GL_TEXTURE1_ARB);