celestiacore.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:147k
- // Return true if anything changed that requires re-rendering. Otherwise, we
- // can skip rendering, keep the GPU idle, and save power.
- bool CelestiaCore::viewUpdateRequired() const
- {
- #if 1
- // Enable after 1.5.0
- return true;
- #else
- bool isPaused = sim->getPauseState() || sim->getTimeScale() == 0.0;
- // See if the camera in any of the views is moving
- bool observersMoving = false;
- for (vector<View*>::const_iterator iter = views.begin(); iter != views.end(); iter++)
- {
- View* v = *iter;
- if (v->observer->getAngularVelocity().length() > 1.0e-10 ||
- v->observer->getVelocity().length() > 1.0e-12)
- {
- observersMoving = true;
- break;
- }
- }
- if (viewChanged ||
- !isPaused ||
- observersMoving ||
- dollyMotion != 0.0 ||
- zoomMotion != 0.0 ||
- scriptState == ScriptRunning ||
- renderer->settingsHaveChanged())
- {
- return true;
- }
- else
- {
- return false;
- }
- #endif
- }
- void CelestiaCore::setViewChanged()
- {
- viewChanged = true;
- }
- void CelestiaCore::splitView(View::Type type, View* av, float splitPos)
- {
- setViewChanged();
- if (av == NULL)
- av = (*activeView);
- bool vertical = ( type == View::VerticalSplit );
- Observer* o = sim->addObserver();
- bool tooSmall = false;
- switch (type) // If active view is too small, don't split it.
- {
- case View::HorizontalSplit:
- if (av->height < 0.2f) tooSmall = true;
- break;
- case View::VerticalSplit:
- if (av->width < 0.2f) tooSmall = true;
- break;
- case View::ViewWindow:
- return;
- break;
- }
- if (tooSmall)
- {
- flash(_("View too small to be split"));
- return;
- }
- flash(_("Added view"));
- // Make the new observer a copy of the old one
- // TODO: This works, but an assignment operator for Observer
- // should be defined.
- *o = *(sim->getActiveObserver());
- float w1, h1, w2, h2;
- if (vertical)
- {
- w1 = av->width * splitPos;
- w2 = av->width - w1;
- h1 = av->height;
- h2 = av->height;
- }
- else
- {
- w1 = av->width;
- w2 = av->width;
- h1 = av->height * splitPos;
- h2 = av->height - h1;
- }
- View* split = new View(type,
- 0,
- av->x,
- av->y,
- av->width,
- av->height);
- split->parent = av->parent;
- if (av->parent != 0)
- {
- if (av->parent->child1 == av)
- av->parent->child1 = split;
- else
- av->parent->child2 = split;
- }
- split->child1 = av;
- av->width = w1;
- av->height = h1;
- av->parent = split;
- View* view = new View(View::ViewWindow,
- o,
- av->x + (vertical ? w1 : 0),
- av->y + (vertical ? 0 : h1),
- w2, h2);
- split->child2 = view;
- view->parent = split;
- view->zoom = av->zoom;
- views.insert(views.end(), split);
- views.insert(views.end(), view);
- setFOVFromZoom();
- }
- void CelestiaCore::setFOVFromZoom()
- {
- for (list<View*>::iterator i = views.begin(); i != views.end(); i++)
- if ((*i)->type == View::ViewWindow)
- {
- double fov = 2 * atan(height * (*i)->height / (screenDpi / 25.4) / 2. / distanceToScreen) / (*i)->zoom;
- (*i)->observer->setFOV((float) fov);
- }
- }
- void CelestiaCore::setZoomFromFOV()
- {
- for (list<View*>::iterator i = views.begin(); i != views.end(); i++)
- if ((*i)->type == View::ViewWindow)
- {
- (*i)->zoom = (float) (2 * atan(height * (*i)->height / (screenDpi / 25.4) / 2. / distanceToScreen) / (*i)->observer->getFOV());
- }
- }
- void CelestiaCore::singleView(View* av)
- {
- setViewChanged();
- if (av == NULL)
- av = (*activeView);
- list<View*>::iterator i = views.begin();
- while(i != views.end())
- {
- if ((*i) != av)
- {
- sim->removeObserver((*i)->observer);
- delete (*i)->observer;
- delete (*i);
- i=views.erase(i);
- }
- else
- i++;
- }
- av->x = 0.0f;
- av->y = 0.0f;
- av->width = 1.0f;
- av->height = 1.0f;
- av->parent = 0;
- av->child1 = 0;
- av->child2 = 0;
- activeView = views.begin();
- sim->setActiveObserver((*activeView)->observer);
- setFOVFromZoom();
- }
- void CelestiaCore::setActiveView(View* v)
- {
- activeView = find(views.begin(),views.end(),v);
- sim->setActiveObserver((*activeView)->observer);
- }
- void CelestiaCore::deleteView(View* v)
- {
- if (v == NULL)
- v = (*activeView);
- if (v->parent == 0) return;
- //Erase view and parent view from views
- list<View*>::iterator i = views.begin();
- while(i != views.end())
- {
- if ((*i == v) || (*i == v->parent))
- i=views.erase(i);
- else
- i++;
- }
- int sign;
- View *sibling;
- if (v->parent->child1 == v)
- {
- sibling = v->parent->child2;
- sign = -1;
- }
- else
- {
- sibling = v->parent->child1;
- sign = 1;
- }
- sibling->parent = v->parent->parent;
- if (v->parent->parent != 0) {
- if (v->parent->parent->child1 == v->parent)
- v->parent->parent->child1 = sibling;
- else
- v->parent->parent->child2 = sibling;
- }
- v->walkTreeResize(sibling, sign);
- sim->removeObserver(v->observer);
- delete(v->observer);
- View* nextActiveView = sibling;
- while (nextActiveView->type != View::ViewWindow)
- nextActiveView = nextActiveView->child1;
- activeView = find(views.begin(),views.end(),nextActiveView);
- sim->setActiveObserver((*activeView)->observer);
- delete(v->parent);
- delete(v);
- if (!showActiveViewFrame)
- flashFrameStart = currentTime;
- setFOVFromZoom();
- }
- bool CelestiaCore::getFramesVisible() const
- {
- return showViewFrames;
- }
- void CelestiaCore::setFramesVisible(bool visible)
- {
- setViewChanged();
- showViewFrames = visible;
- }
- bool CelestiaCore::getActiveFrameVisible() const
- {
- return showActiveViewFrame;
- }
- void CelestiaCore::setActiveFrameVisible(bool visible)
- {
- setViewChanged();
- showActiveViewFrame = visible;
- }
- void CelestiaCore::setContextMenuCallback(ContextMenuFunc callback)
- {
- contextMenuCallback = callback;
- }
- Renderer* CelestiaCore::getRenderer() const
- {
- return renderer;
- }
- Simulation* CelestiaCore::getSimulation() const
- {
- return sim;
- }
- void CelestiaCore::showText(string s,
- int horig, int vorig,
- int hoff, int voff,
- double duration)
- {
- messageText = s;
- messageHOrigin = horig;
- messageVOrigin = vorig;
- messageHOffset = hoff;
- messageVOffset = voff;
- messageStart = currentTime;
- messageDuration = duration;
- }
- int CelestiaCore::getTextWidth(string s) const
- {
- return titleFont->getWidth(s);
- }
- static FormattedNumber SigDigitNum(double v, int digits)
- {
- return FormattedNumber(v, digits,
- FormattedNumber::GroupThousands |
- FormattedNumber::SignificantDigits);
- }
- static void displayDistance(Overlay& overlay, double distance)
- {
- const char* units = "";
- if (abs(distance) >= astro::parsecsToLightYears(1e+6))
- {
- units = "Mpc";
- distance = astro::lightYearsToParsecs(distance) / 1e+6;
- }
- else if (abs(distance) >= 0.5 * astro::parsecsToLightYears(1e+3))
- {
- units = "Kpc";
- distance = astro::lightYearsToParsecs(distance) / 1e+3;
- }
- else if (abs(distance) >= astro::AUtoLightYears(1000.0f))
- {
- units = _("ly");
- }
- else if (abs(distance) >= astro::kilometersToLightYears(10000000.0))
- {
- units = _("au");
- distance = astro::lightYearsToAU(distance);
- }
- else if (abs(distance) > astro::kilometersToLightYears(1.0f))
- {
- units = "km";
- distance = astro::lightYearsToKilometers(distance);
- }
- else
- {
- units = "m";
- distance = astro::lightYearsToKilometers(distance) * 1000.0f;
- }
- overlay << SigDigitNum(distance, 5) << ' ' << units;
- }
- static void displayDuration(Overlay& overlay, double days)
- {
- if (days > 1.0)
- overlay << FormattedNumber(days, 3, FormattedNumber::GroupThousands) << _(" days");
- else if (days > 1.0 / 24.0)
- overlay << FormattedNumber(days * 24.0, 3, FormattedNumber::GroupThousands) << _(" hours");
- else if (days > 1.0 / (24.0 * 60.0))
- overlay << FormattedNumber(days * 24.0 * 60.0, 3, FormattedNumber::GroupThousands) << _(" minutes");
- else
- overlay << FormattedNumber(days * 24.0 * 60.0 * 60.0, 3, FormattedNumber::GroupThousands) << " seconds";
- }
- // Display a positive angle as degrees, minutes, and seconds. If the angle is less than one
- // degree, only minutes and seconds are shown; if the angle is less than one minute, only
- // seconds are displayed.
- static void displayAngle(Overlay& overlay, double angle)
- {
- int degrees, minutes;
- double seconds;
- astro::decimalToDegMinSec(angle, degrees, minutes, seconds);
- if (degrees > 0)
- {
- overlay.oprintf("%d%s %02d' %.1f"",
- degrees, UTF8_DEGREE_SIGN, abs(minutes), abs(seconds));
- }
- else if (minutes > 0)
- {
- overlay.oprintf("%02d' %.1f"", abs(minutes), abs(seconds));
- }
- else
- {
- overlay.oprintf("%.2f"", abs(seconds));
- }
- }
- static void displayDeclination(Overlay& overlay, double angle)
- {
- int degrees, minutes;
- double seconds;
- astro::decimalToDegMinSec(angle, degrees, minutes, seconds);
- char sign = '+';
- if (angle < 0.0)
- sign = '-';
- overlay.oprintf("%c%d%s %02d' %.1f"",
- sign, abs(degrees), UTF8_DEGREE_SIGN, abs(minutes), abs(seconds));
- }
- static void displayRightAscension(Overlay& overlay, double angle)
- {
- int hours, minutes;
- double seconds;
- astro::decimalToHourMinSec(angle, hours, minutes, seconds);
- overlay.oprintf("%dh %02dm %.1fs",
- hours, abs(minutes), abs(seconds));
- }
- static void displayApparentDiameter(Overlay& overlay,
- double radius,
- double distance)
- {
- if (distance > radius)
- {
- double arcSize = radToDeg(asin(radius / distance) * 2.0);
- // Only display the arc size if it's less than 160 degrees and greater
- // than one second--otherwise, it's probably not interesting data.
- if (arcSize < 160.0 && arcSize > 1.0 / 3600.0)
- {
- overlay << _("Apparent diameter: ");
- displayAngle(overlay, arcSize);
- overlay << 'n';
- }
- }
- }
- static void displayApparentMagnitude(Overlay& overlay,
- float absMag,
- double distance)
- {
- float appMag = absMag;
- if (distance > 32.6167)
- {
- appMag = astro::absToAppMag(absMag, (float) distance);
- overlay << _("Apparent magnitude: ");
- }
- else
- {
- overlay << _("Absolute magnitude: ");
- }
- overlay.oprintf("%.1fn", appMag);
- }
- static void displayRADec(Overlay& overlay, Vec3d v)
- {
- double phi = atan2(v.x, v.z) - PI / 2;
- if (phi < 0)
- phi = phi + 2 * PI;
- double theta = atan2(sqrt(v.x * v.x + v.z * v.z), v.y);
- if (theta > 0)
- theta = PI / 2 - theta;
- else
- theta = -PI / 2 - theta;
- double ra = radToDeg(phi);
- double dec = radToDeg(theta);
- overlay << _("RA: ");
- overlay << " ";
- displayRightAscension(overlay, ra);
- overlay << endl;
- overlay << _("Dec: ");
- displayDeclination(overlay, dec);
- overlay << endl;
- }
- // Display nicely formatted planetocentric/planetographic coordinates.
- // The latitude and longitude parameters are angles in radians, altitude
- // is in kilometers.
- static void displayPlanetocentricCoords(Overlay& overlay,
- const Body& body,
- double longitude,
- double latitude,
- double altitude,
- bool showAltitude)
- {
- char ewHemi = ' ';
- char nsHemi = ' ';
- double lon = 0.0;
- double lat = 0.0;
- // Terrible hack for Earth and Moon longitude conventions. Fix by
- // adding a field to specify the longitude convention in .ssc files.
- if (body.getName() == "Earth" || body.getName() == "Moon")
- {
- if (latitude < 0.0)
- nsHemi = 'S';
- else if (latitude > 0.0)
- nsHemi = 'N';
- if (longitude < 0.0)
- ewHemi = 'W';
- else if (longitude > 0.0f)
- ewHemi = 'E';
- lon = (float) abs(radToDeg(longitude));
- lat = (float) abs(radToDeg(latitude));
- }
- else
- {
- // Swap hemispheres if the object is a retrograde rotator
- Quatd q = ~body.getEclipticToEquatorial(astro::J2000);
- bool retrograde = (Vec3d(0.0, 1.0, 0.0) * q.toMatrix3()).y < 0.0;
- if ((latitude < 0.0) ^ retrograde)
- nsHemi = 'S';
- else if ((latitude > 0.0) ^ retrograde)
- nsHemi = 'N';
-
- if (retrograde)
- ewHemi = 'E';
- else
- ewHemi = 'W';
- lon = -radToDeg(longitude);
- if (lon < 0.0)
- lon += 360.0;
- lat = abs(radToDeg(latitude));
- }
- overlay.unsetf(ios::fixed);
- overlay << setprecision(6);
- overlay << lat << nsHemi << ' ' << lon << ewHemi;
- if (showAltitude)
- overlay << ' ' << altitude << _("km") << endl;
- overlay << endl;
- }
- #if 0
- // Show the planetocentric latitude, longitude, and altitude of a
- // observer.
- static void displayObserverPlanetocentricCoords(Overlay& overlay,
- Body& body,
- const UniversalCoord& observerPos,
- double tdb)
- {
- // Get the observer position in body-centered ecliptical coordinates
- Vec3d ecl = observerPos - Selection(&body).getPosition(tdb);
- ecl *= astro::microLightYearsToKilometers(1.0);
- Vec3d pc = body.eclipticToPlanetocentric(ecl, tdb);
- displayPlanetocentricCoords(overlay, body, pc.x, pc.y, pc.z, true);
- }
- #endif
- static void displayStarInfo(Overlay& overlay,
- int detail,
- Star& star,
- const Universe& universe,
- double distance)
- {
- overlay << _("Distance: ");
- displayDistance(overlay, distance);
- overlay << 'n';
- if (!star.getVisibility())
- {
- overlay << _("Star system barycentern");
- }
- else
- {
- overlay.oprintf(_("Abs (app) mag: %.2f (%.2f)n"),
- star.getAbsoluteMagnitude(),
- astro::absToAppMag(star.getAbsoluteMagnitude(),
- (float) distance));
- if (star.getLuminosity() > 1.0e-10f)
- overlay << _("Luminosity: ") << SigDigitNum(star.getLuminosity(), 3) << _("x Sun") << "n";
- overlay << _("Class: ");
- if (star.getSpectralType()[0] == 'Q')
- overlay << _("Neutron star");
- else if (star.getSpectralType()[0] == 'X')
- overlay << _("Black hole");
- else
- overlay << star.getSpectralType();
- overlay << 'n';
- displayApparentDiameter(overlay, star.getRadius(),
- astro::lightYearsToKilometers(distance));
- if (detail > 1)
- {
- overlay << _("Surface temp: ") << SigDigitNum(star.getTemperature(), 3) << " Kn";
- float solarRadii = star.getRadius() / 6.96e5f;
- overlay << _("Radius: ");
- if (solarRadii > 0.01f)
- {
- overlay << SigDigitNum(star.getRadius() / 696000.0f, 2) << " " << _("Rsun")
- << " (" << SigDigitNum(star.getRadius(), 3) << " km" << ")n";
- }
- else
- {
- overlay << SigDigitNum(star.getRadius(), 3) << " kmn";
- }
- if (star.getRotationModel()->isPeriodic())
- {
- overlay << _("Rotation period: ");
- float period = (float) star.getRotationModel()->getPeriod();
- displayDuration(overlay, period);
- overlay << 'n';
- }
- }
- }
-
- if (detail > 1)
- {
- SolarSystem* sys = universe.getSolarSystem(&star);
- if (sys != NULL && sys->getPlanets()->getSystemSize() != 0)
- overlay << _("Planetary companions presentn");
- }
- }
- static void displayDSOinfo(Overlay& overlay, const DeepSkyObject& dso, double distance)
- {
- char descBuf[128];
- dso.getDescription(descBuf, sizeof(descBuf));
- overlay << descBuf << 'n';
- if (distance >= 0)
- {
- overlay << _("Distance: ");
- displayDistance(overlay, distance);
- }
- else
- {
- overlay << _("Distance from center: ");
- displayDistance(overlay, distance + dso.getRadius());
- }
- overlay << 'n';
- overlay << _("Radius: ");
- displayDistance(overlay, dso.getRadius());
- overlay << 'n';
- displayApparentDiameter(overlay, dso.getRadius(), distance);
- if (dso.getAbsoluteMagnitude() > DSO_DEFAULT_ABS_MAGNITUDE)
- {
- displayApparentMagnitude(overlay,
- dso.getAbsoluteMagnitude(),
- distance);
- }
- }
- static void displayPlanetInfo(Overlay& overlay,
- int detail,
- Body& body,
- double t,
- double distance,
- Vec3d viewVec)
- {
- double kmDistance = astro::lightYearsToKilometers(distance);
- overlay << _("Distance: ");
- distance = astro::kilometersToLightYears(kmDistance - body.getRadius());
- displayDistance(overlay, distance);
- overlay << 'n';
- if (body.getClassification() == Body::Invisible)
- {
- return;
- }
- overlay << _("Radius: ");
- distance = astro::kilometersToLightYears(body.getRadius());
- displayDistance(overlay, distance);
- overlay << 'n';
- displayApparentDiameter(overlay, body.getRadius(), kmDistance);
- // Display the phase angle
- // Find the parent star of the body. This can be slightly complicated if
- // the body orbits a barycenter instead of a star.
- Selection parent = Selection(&body).parent();
- while (parent.body() != NULL)
- parent = parent.parent();
- if (parent.star() != NULL)
- {
- bool showPhaseAngle = false;
- Star* sun = parent.star();
- if (sun->getVisibility())
- {
- showPhaseAngle = true;
- }
- else if (sun->getOrbitingStars())
- {
- // The planet's orbit is defined with respect to a barycenter. If there's
- // a single star orbiting the barycenter, we'll compute the phase angle
- // for the planet with respect to that star. If there are no stars, the
- // planet is an orphan, drifting through space with no star. We also skip
- // displaying the phase angle when there are multiple stars (for now.)
- if (sun->getOrbitingStars()->size() == 1)
- {
- sun = sun->getOrbitingStars()->at(0);
- showPhaseAngle = sun->getVisibility();
- }
- }
- if (showPhaseAngle)
- {
- Vec3d sunVec = Selection(&body).getPosition(t) - Selection(sun).getPosition(t);
- sunVec.normalize();
- double cosPhaseAngle = sunVec * ((1.0 / viewVec.length()) * viewVec);
- double phaseAngle = acos(cosPhaseAngle);
- overlay.oprintf("Phase angle: %.1f%sn", radToDeg(phaseAngle), UTF8_DEGREE_SIGN);
- }
- }
- if (detail > 1)
- {
- if (body.getRotationModel(t)->isPeriodic())
- {
- overlay << _("Rotation period: ");
- displayDuration(overlay, body.getRotationModel(t)->getPeriod());
- overlay << 'n';
- }
- PlanetarySystem* system = body.getSystem();
- if (system != NULL)
- {
- const Star* sun = system->getStar();
- if (sun != NULL)
- {
- double distFromSun = body.getAstrocentricPosition(t).distanceFromOrigin();
- float planetTemp = sun->getTemperature() *
- (float) (::pow(1.0 - body.getAlbedo(), 0.25) *
- sqrt(sun->getRadius() / (2.0 * distFromSun)));
- overlay << setprecision(0);
- overlay << _("Temperature: ") << planetTemp << " Kn";
- overlay << setprecision(3);
- }
- #if 0
- // Code to display apparent magnitude. Disabled because it's not very
- // accurate. Too many simplifications are used when computing the amount
- // of light reflected from a body.
- Point3d bodyPos = body.getAstrocentricPosition(t);
- float appMag = body.getApparentMagnitude(*sun,
- bodyPos - Point3d(0, 0, 0),
- viewVec);
- overlay.oprintf(_("Apparent mag: %.2fn"), appMag);
- #endif
- }
- }
- }
- static void displayLocationInfo(Overlay& overlay,
- Location& location,
- double distance)
- {
- overlay << _("Distance: ");
- displayDistance(overlay, distance);
- overlay << 'n';
- Body* body = location.getParentBody();
- if (body != NULL)
- {
- Vec3f locPos = location.getPosition();
- Vec3d lonLatAlt = body->cartesianToPlanetocentric(Vec3d(locPos.x, locPos.y, locPos.z));
- displayPlanetocentricCoords(overlay, *body,
- lonLatAlt.x, lonLatAlt.y, lonLatAlt.z, false);
- }
- }
- static void displaySelectionName(Overlay& overlay,
- const Selection& sel,
- const Universe& univ)
- {
- switch (sel.getType())
- {
- case Selection::Type_Body:
- overlay << sel.body()->getName(true).c_str();
- break;
- case Selection::Type_DeepSky:
- overlay << univ.getDSOCatalog()->getDSOName(sel.deepsky(), true);
- break;
- case Selection::Type_Star:
- //displayStarName(overlay, *(sel.star()), *univ.getStarCatalog());
- overlay << ReplaceGreekLetterAbbr(univ.getStarCatalog()->getStarName(*sel.star(), true));
- break;
- case Selection::Type_Location:
- overlay << sel.location()->getName(true).c_str();
- break;
- default:
- break;
- }
- }
- static void showViewFrame(const View* v, int width, int height)
- {
- glBegin(GL_LINE_LOOP);
- glVertex3f(v->x * width, v->y * height, 0.0f);
- glVertex3f(v->x * width, (v->y + v->height) * height - 1, 0.0f);
- glVertex3f((v->x + v->width) * width - 1, (v->y + v->height) * height - 1, 0.0f);
- glVertex3f((v->x + v->width) * width - 1, v->y * height, 0.0f);
- glEnd();
- }
- void CelestiaCore::renderOverlay()
- {
- #ifdef CELX
- if (luaHook) luaHook->callLuaHook(this,"renderoverlay");
- #endif
- if (font == NULL)
- return;
- overlay->setFont(font);
- int fontHeight = font->getHeight();
- int emWidth = font->getWidth("M");
- overlay->begin();
- if (views.size() > 1)
- {
- // Render a thin border arround all views
- if (showViewFrames || resizeSplit)
- {
- glLineWidth(1.0f);
- glDisable(GL_TEXTURE_2D);
- glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
- for(list<View*>::iterator i = views.begin(); i != views.end(); i++)
- if ((*i)->type == View::ViewWindow)
- showViewFrame(*i, width, height);
- }
- glLineWidth(1.0f);
- // Render a very simple border around the active view
- View* av = (*activeView);
- if (showActiveViewFrame)
- {
- glLineWidth(2.0f);
- glDisable(GL_TEXTURE_2D);
- glColor4f(0.5f, 0.5f, 1.0f, 1.0f);
- showViewFrame(av, width, height);
- glLineWidth(1.0f);
- }
- if (currentTime < flashFrameStart + 0.5)
- {
- glLineWidth(8.0f);
- glColor4f(0.5f, 0.5f, 1.0f,
- (float) (1.0 - (currentTime - flashFrameStart) / 0.5));
- showViewFrame(av, width, height);
- glLineWidth(1.0f);
- }
- }
- setlocale(LC_NUMERIC, "");
- if (hudDetail > 0 && (overlayElements & ShowTime))
- {
- double lt = 0.0;
-
- if (sim->getSelection().getType() == Selection::Type_Body &&
- (sim->getTargetSpeed() < 0.99 *
- astro::kilometersToMicroLightYears(astro::speedOfLight)))
- {
- if (lightTravelFlag)
- {
- Vec3d v = sim->getSelection().getPosition(sim->getTime()) -
- sim->getObserver().getPosition();
- // light travel time in days
- lt = astro::microLightYearsToKilometers(v.length()) / (86400.0 * astro::speedOfLight);
- }
- }
- else
- {
- lt = 0.0;
- }
- double tdb = sim->getTime() + lt;
- astro::Date d = timeZoneBias != 0?astro::TDBtoLocal(tdb):astro::TDBtoUTC(tdb);
- const char* dateStr = d.toCStr(dateFormat);
- int dateWidth = (font->getWidth(dateStr)/(emWidth * 3) + 2) * emWidth * 3;
- if (dateWidth > dateStrWidth) dateStrWidth = dateWidth;
- // Time and date
- glPushMatrix();
- glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
- glTranslatef( (float) (width - dateStrWidth),
- (float) (height - fontHeight),
- 0.0f);
- overlay->beginText();
- overlay->print(dateStr);
- if (lightTravelFlag && lt > 0.0)
- {
- glColor4f(0.42f, 1.0f, 1.0f, 1.0f);
- *overlay << _(" LT");
- glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
- }
- *overlay << 'n';
- {
- if (abs(abs(sim->getTimeScale()) - 1) < 1e-6)
- {
- if (sign(sim->getTimeScale()) == 1)
- *overlay << _("Real time");
- else
- *overlay << _("-Real time");
- }
- else if (abs(sim->getTimeScale()) < MinimumTimeRate)
- {
- *overlay << _("Time stopped");
- }
- else if (abs(sim->getTimeScale()) > 1.0)
- {
- overlay->oprintf(TIMERATE_PRINTF_FORMAT, sim->getTimeScale());
- *overlay << UTF8_MULTIPLICATION_SIGN << _(" faster");
- }
- else
- {
- overlay->oprintf(TIMERATE_PRINTF_FORMAT, 1.0 / sim->getTimeScale());
- *overlay << UTF8_MULTIPLICATION_SIGN << _(" slower");
- }
- if (sim->getPauseState() == true)
- {
- glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
- *overlay << _(" (Paused)");
- }
- }
- overlay->endText();
- glPopMatrix();
- }
- if (hudDetail > 0 && (overlayElements & ShowVelocity))
- {
- // Speed
- glPushMatrix();
- glTranslatef(0.0f, (float) (fontHeight * 2 + 5), 0.0f);
- glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
- overlay->beginText();
- *overlay << 'n';
- if (showFPSCounter)
- *overlay << _("FPS: ") << SigDigitNum(fps, 3);
- overlay->setf(ios::fixed);
- *overlay << _("nSpeed: ");
- double speed = sim->getObserver().getVelocity().length();
- if (speed < astro::kilometersToMicroLightYears(1.0f))
- *overlay << SigDigitNum(astro::microLightYearsToKilometers(speed) * 1000.0f, 3) << _(" m/s");
- else if (speed < astro::kilometersToMicroLightYears(10000.0f))
- *overlay << SigDigitNum(astro::microLightYearsToKilometers(speed), 3) << _(" km/s");
- else if (speed < astro::kilometersToMicroLightYears((float) astro::speedOfLight * 100.0f))
- *overlay << SigDigitNum(astro::microLightYearsToKilometers(speed) / astro::speedOfLight, 3) << 'c';
- else if (speed < astro::AUtoMicroLightYears(1000.0f))
- *overlay << SigDigitNum(astro::microLightYearsToAU(speed), 3) << _(" AU/s");
- else
- *overlay << SigDigitNum(speed * 1e-6, 3) << _(" ly/s");
- overlay->endText();
- glPopMatrix();
- }
- if (hudDetail > 0 && (overlayElements & ShowFrame))
- {
- // Field of view and camera mode in lower right corner
- glPushMatrix();
- glTranslatef((float) (width - emWidth * 15),
- (float) (fontHeight * 3 + 5), 0.0f);
- overlay->beginText();
- glColor4f(0.6f, 0.6f, 1.0f, 1);
- if (sim->getObserverMode() == Observer::Travelling)
- {
- *overlay << _("Travelling ");
- double timeLeft = sim->getArrivalTime() - sim->getRealTime();
- if (timeLeft >= 1)
- *overlay << '(' << FormattedNumber(timeLeft, 0, FormattedNumber::GroupThousands) << ')';
- *overlay << 'n';
- }
- else
- {
- *overlay << 'n';
- }
- if (!sim->getTrackedObject().empty())
- {
- *overlay << _("Track ");
- displaySelectionName(*overlay, sim->getTrackedObject(),
- *sim->getUniverse());
- }
- *overlay << 'n';
- {
- //FrameOfReference frame = sim->getFrame();
- Selection refObject = sim->getFrame()->getRefObject();
- ObserverFrame::CoordinateSystem coordSys = sim->getFrame()->getCoordinateSystem();
- switch (coordSys)
- {
- case ObserverFrame::Ecliptical:
- *overlay << _("Follow ");
- displaySelectionName(*overlay, refObject,
- *sim->getUniverse());
- break;
- case ObserverFrame::BodyFixed:
- *overlay << _("Sync Orbit ");
- displaySelectionName(*overlay, refObject,
- *sim->getUniverse());
- break;
- case ObserverFrame::PhaseLock:
- *overlay << _("Lock ");
- displaySelectionName(*overlay, refObject,
- *sim->getUniverse());
- *overlay << " -> ";
- displaySelectionName(*overlay, sim->getFrame()->getTargetObject(),
- *sim->getUniverse());
- break;
- case ObserverFrame::Chase:
- *overlay << _("Chase ");
- displaySelectionName(*overlay, refObject,
- *sim->getUniverse());
- break;
- default:
- break;
- }
- *overlay << 'n';
- }
- glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
- // Field of view
- float fov = radToDeg(sim->getActiveObserver()->getFOV());
- overlay->oprintf(_("FOV: "));
- displayAngle(*overlay, fov);
- overlay->oprintf(" (%.2f%s)n", (*activeView)->zoom,
- UTF8_MULTIPLICATION_SIGN);
- overlay->endText();
- glPopMatrix();
- }
- // Selection info
- Selection sel = sim->getSelection();
- if (!sel.empty() && hudDetail > 0 && (overlayElements & ShowSelection))
- {
- glPushMatrix();
- glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
- glTranslatef(0.0f, (float) (height - titleFont->getHeight()), 0.0f);
- overlay->beginText();
- Vec3d v = sel.getPosition(sim->getTime()) -
- sim->getObserver().getPosition();
- switch (sel.getType())
- {
- case Selection::Type_Star:
- {
- if (sel != lastSelection)
- {
- lastSelection = sel;
- selectionNames = sim->getUniverse()->getStarCatalog()->getStarNameList(*sel.star());
- // Skip displaying the English name if a localized version is present.
- string starName = sim->getUniverse()->getStarCatalog()->getStarName(*sel.star());
- string locStarName = sim->getUniverse()->getStarCatalog()->getStarName(*sel.star(), true);
- if (sel.star()->getCatalogNumber() == 0 && selectionNames.find("Sun") != string::npos && (const char*) "Sun" != _("Sun"))
- {
- string::size_type startPos = selectionNames.find("Sun");
- string::size_type endPos = selectionNames.find(_("Sun"));
- selectionNames = selectionNames.erase(startPos, endPos - startPos);
- }
- else if (selectionNames.find(starName) != string::npos && starName != locStarName)
- {
- string::size_type startPos = selectionNames.find(locStarName);
- selectionNames = selectionNames.substr(startPos);
- }
- }
- overlay->setFont(titleFont);
- *overlay << selectionNames;
- overlay->setFont(font);
- *overlay << 'n';
- displayStarInfo(*overlay,
- hudDetail,
- *(sel.star()),
- *(sim->getUniverse()),
- v.length() * 1e-6);
- }
- break;
- case Selection::Type_DeepSky:
- {
- if (sel != lastSelection)
- {
- lastSelection = sel;
- selectionNames = sim->getUniverse()->getDSOCatalog()->getDSONameList(sel.deepsky());
- // Skip displaying the English name if a localized version is present.
- string DSOName = sim->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky());
- string locDSOName = sim->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky(), true);
- if (selectionNames.find(DSOName) != string::npos && DSOName != locDSOName)
- {
- string::size_type startPos = selectionNames.find(locDSOName);
- selectionNames = selectionNames.substr(startPos);
- }
- }
- overlay->setFont(titleFont);
- *overlay << selectionNames;
- overlay->setFont(font);
- *overlay << 'n';
- displayDSOinfo(*overlay, *sel.deepsky(),
- v.length() * 1e-6 - sel.deepsky()->getRadius());
- }
- break;
- case Selection::Type_Body:
- {
- // Show all names for the body
- if (sel != lastSelection)
- {
- lastSelection = sel;
- selectionNames = "";
- const vector<string>& names = sel.body()->getNames();
- // Skip displaying the primary name if there's a localized version
- // of the name.
- vector<string>::const_iterator firstName = names.begin();
- if (sel.body()->hasLocalizedName())
- firstName++;
- for (vector<string>::const_iterator iter = firstName; iter != names.end(); iter++)
- {
- if (iter != firstName)
- selectionNames += " / ";
- // Use localized version of parent name in alternative names.
- string alias = *iter;
- Selection parent = sel.parent();
- if (parent.body() != NULL)
- {
- string parentName = parent.body()->getName();
- string locParentName = parent.body()->getName(true);
- string::size_type startPos = alias.find(parentName);
- if (startPos != string::npos)
- alias.replace(startPos, parentName.length(), locParentName);
- }
- selectionNames += alias;
- }
- }
- overlay->setFont(titleFont);
- *overlay << selectionNames;
- overlay->setFont(font);
- *overlay << 'n';
- displayPlanetInfo(*overlay,
- hudDetail,
- *(sel.body()),
- sim->getTime(),
- v.length() * 1e-6,
- v * astro::microLightYearsToKilometers(1.0));
- }
- break;
- case Selection::Type_Location:
- overlay->setFont(titleFont);
- *overlay << sel.location()->getName(true).c_str();
- overlay->setFont(font);
- *overlay << 'n';
- displayLocationInfo(*overlay,
- *(sel.location()),
- v.length() * 1e-6);
- break;
- default:
- break;
- }
-
- // Display RA/Dec for the selection, but only when the observer is near
- // the Earth.
- Selection refObject = sim->getFrame()->getRefObject();
- if (refObject.body() && refObject.body()->getName() == "Earth")
- {
- Body* earth = refObject.body();
- UniversalCoord observerPos = sim->getObserver().getPosition();
- double distToEarth = (observerPos - refObject.getPosition(sim->getTime())).length();
- distToEarth = astro::microLightYearsToKilometers(distToEarth) - earth->getRadius();
- if (distToEarth < 1000.0)
- {
- #if 1
- // Code to show the geocentric RA/Dec
- // Only show the coordinates for stars and deep sky objects, where
- // the geocentric values will match the apparent values for observers
- // near the Earth.
- if (sel.star() != NULL || sel.deepsky() != NULL)
- {
- Vec3d v = sel.getPosition(sim->getTime()) - Selection(earth).getPosition(sim->getTime());
- v = v * Mat3d::xrotation(-astro::J2000Obliquity);
- displayRADec(*overlay, v);
- }
- #else
- // Code to display the apparent RA/Dec for the observer
- // Don't show RA/Dec for the Earth itself
- if (sel.body() != earth)
- {
- Vec3d vect = sel.getPosition(sim->getTime()) - observerPos;
- vect = vect * Mat3d::xrotation(-astro::J2000Obliquity);
- displayRADec(*overlay, vect);
- }
- // Show the geocentric coordinates of the observer, required for
- // converting the selection RA/Dec from observer-centric to some
- // other coordinate system.
- // TODO: We should really show the planetographic (for Earth, geodetic)
- // coordinates.
- displayObserverPlanetocentricCoords(*overlay,
- *earth,
- observerPos,
- sim->getTime());
- #endif
- }
- }
- overlay->endText();
- glPopMatrix();
- }
- // Text input
- if (textEnterMode & KbAutoComplete)
- {
- overlay->setFont(titleFont);
- glPushMatrix();
- glColor4f(0.7f, 0.7f, 1.0f, 0.2f);
- overlay->rect(0.0f, 0.0f, (float) width, 100.0f);
- glTranslatef(0.0f, fontHeight * 3.0f + 35.0f, 0.0f);
- glColor4f(0.6f, 0.6f, 1.0f, 1.0f);
- overlay->beginText();
- *overlay << _("Target name: ") << ReplaceGreekLetterAbbr(typedText);
- overlay->endText();
- overlay->setFont(font);
- if (typedTextCompletion.size() >= 1)
- {
- int nb_cols = 4;
- int nb_lines = 3;
- int start = 0;
- glTranslatef(3.0f, -font->getHeight() - 3.0f, 0.0f);
- vector<std::string>::const_iterator iter = typedTextCompletion.begin();
- if (typedTextCompletionIdx >= nb_cols * nb_lines)
- {
- start = (typedTextCompletionIdx / nb_lines + 1 - nb_cols) * nb_lines;
- iter += start;
- }
- for (int i=0; iter < typedTextCompletion.end() && i < nb_cols; i++)
- {
- glPushMatrix();
- overlay->beginText();
- for (int j = 0; iter < typedTextCompletion.end() && j < nb_lines; iter++, j++)
- {
- if (i * nb_lines + j == typedTextCompletionIdx - start)
- glColor4f(1.0f, 0.6f, 0.6f, 1);
- else
- glColor4f(0.6f, 0.6f, 1.0f, 1);
- *overlay << ReplaceGreekLetterAbbr(*iter) << "n";
- }
- overlay->endText();
- glPopMatrix();
- glTranslatef((float) (width/nb_cols), 0.0f, 0.0f);
- }
- }
- glPopMatrix();
- overlay->setFont(font);
- }
- // Text messages
- if (messageText != "" && currentTime < messageStart + messageDuration)
- {
- int emWidth = titleFont->getWidth("M");
- int fontHeight = titleFont->getHeight();
- int x = messageHOffset * emWidth;
- int y = messageVOffset * fontHeight;
- if (messageHOrigin == 0)
- x += width / 2;
- else if (messageHOrigin > 0)
- x += width;
- if (messageVOrigin == 0)
- y += height / 2;
- else if (messageVOrigin > 0)
- y += height;
- else if (messageVOrigin < 0)
- y -= fontHeight;
- overlay->setFont(titleFont);
- glPushMatrix();
- float alpha = 1.0f;
- if (currentTime > messageStart + messageDuration - 0.5)
- alpha = (float) ((messageStart + messageDuration - currentTime) / 0.5);
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glTranslatef((float) x, (float) y, 0.0f);
- overlay->beginText();
- *overlay << _(messageText.c_str());
- overlay->endText();
- glPopMatrix();
- overlay->setFont(font);
- }
- if (movieCapture != NULL)
- {
- int movieWidth = movieCapture->getWidth();
- int movieHeight = movieCapture->getHeight();
- glPushMatrix();
- glColor4f(1, 0, 0, 1);
- overlay->rect((float) ((width - movieWidth) / 2 - 1),
- (float) ((height - movieHeight) / 2 - 1),
- (float) (movieWidth + 1),
- (float) (movieHeight + 1), false);
- glTranslatef((float) ((width - movieWidth) / 2),
- (float) ((height + movieHeight) / 2 + 2), 0.0f);
- *overlay << movieWidth << 'x' << movieHeight << _(" at ") <<
- movieCapture->getFrameRate() << _(" fps");
- if (recording)
- *overlay << _(" Recording");
- else
- *overlay << _(" Paused");
- glPopMatrix();
- glPushMatrix();
- glTranslatef((float) ((width + movieWidth) / 2 - emWidth * 5),
- (float) ((height + movieHeight) / 2 + 2),
- 0.0f);
- float sec = movieCapture->getFrameCount() /
- movieCapture->getFrameRate();
- int min = (int) (sec / 60);
- sec -= min * 60.0f;
- overlay->oprintf("%3d:%05.2f", min, sec);
- glPopMatrix();
- glPushMatrix();
- glTranslatef((float) ((width - movieWidth) / 2),
- (float) ((height - movieHeight) / 2 - fontHeight - 2),
- 0.0f);
- *overlay << _("F11 Start/Pause F12 Stop");
- glPopMatrix();
- glPopMatrix();
- }
- if (editMode)
- {
- glPushMatrix();
- glTranslatef((float) ((width - font->getWidth(_("Edit Mode"))) / 2),
- (float) (height - fontHeight), 0.0f);
- glColor4f(1, 0, 1, 1);
- *overlay << _("Edit Mode");
- glPopMatrix();
- }
- // Show logo at start
- if (logoTexture != NULL)
- {
- glEnable(GL_TEXTURE_2D);
- if (currentTime < 5.0)
- {
- int xSize = (int) (logoTexture->getWidth() * 0.8f);
- int ySize = (int) (logoTexture->getHeight() * 0.8f);
- int left = (width - xSize) / 2;
- int bottom = height / 2;
- float topAlpha, botAlpha;
- if (currentTime < 4.0)
- {
- botAlpha = (float) clamp(currentTime / 1.0);
- topAlpha = (float) clamp(currentTime / 4.0);
- }
- else
- {
- botAlpha = topAlpha = (float) (5.0 - currentTime);
- }
- logoTexture->bind();
- glBegin(GL_QUADS);
- glColor4f(0.8f, 0.8f, 1.0f, botAlpha);
- //glColor4f(1.0f, 1.0f, 1.0f, botAlpha);
- glTexCoord2f(0.0f, 1.0f);
- glVertex2i(left, bottom);
- glTexCoord2f(1.0f, 1.0f);
- glVertex2i(left + xSize, bottom);
- glColor4f(0.6f, 0.6f, 1.0f, topAlpha);
- //glColor4f(1.0f, 1.0f, 1.0f, topAlpha);
- glTexCoord2f(1.0f, 0.0f);
- glVertex2i(left + xSize, bottom + ySize);
- glTexCoord2f(0.0f, 0.0f);
- glVertex2i(left, bottom + ySize);
- glEnd();
- }
- else
- {
- delete logoTexture;
- logoTexture = NULL;
- }
- }
- overlay->end();
- setlocale(LC_NUMERIC, "C");
- }
- class SolarSystemLoader : public EnumFilesHandler
- {
- public:
- Universe* universe;
- ProgressNotifier* notifier;
- SolarSystemLoader(Universe* u, ProgressNotifier* pn) : universe(u), notifier(pn) {};
- bool process(const string& filename)
- {
- if (DetermineFileType(filename) == Content_CelestiaCatalog)
- {
- string fullname = getPath() + '/' + filename;
- clog << _("Loading solar system catalog: ") << fullname << 'n';
- if (notifier)
- notifier->update(filename);
- ifstream solarSysFile(fullname.c_str(), ios::in);
- if (solarSysFile.good())
- {
- LoadSolarSystemObjects(solarSysFile,
- *universe,
- getPath());
- }
- }
- return true;
- };
- };
- template <class OBJDB> class CatalogLoader : public EnumFilesHandler
- {
- public:
- OBJDB* objDB;
- string typeDesc;
- ContentType contentType;
- ProgressNotifier* notifier;
- CatalogLoader(OBJDB* db,
- const std::string& typeDesc,
- const ContentType& contentType,
- ProgressNotifier* pn) :
- objDB (db),
- typeDesc (typeDesc),
- contentType(contentType),
- notifier(pn)
- {
- }
- bool process(const string& filename)
- {
- if (DetermineFileType(filename) == contentType)
- {
- string fullname = getPath() + '/' + filename;
- clog << _("Loading ") << typeDesc << " catalog: " << fullname << 'n';
- if (notifier)
- notifier->update(filename);
- ifstream catalogFile(fullname.c_str(), ios::in);
- if (catalogFile.good())
- {
- bool success = objDB->load(catalogFile, getPath());
- if (!success)
- {
- //DPRINTF(0, _("Error reading star file: %sn"), fullname.c_str());
- DPRINTF(0, "Error reading %s catalog file: %sn", typeDesc.c_str(), fullname.c_str());
- }
- }
- }
- return true;
- }
- };
- typedef CatalogLoader<StarDatabase> StarLoader;
- typedef CatalogLoader<DSODatabase> DeepSkyLoader;
- bool CelestiaCore::initSimulation(const string* configFileName,
- const vector<string>* extrasDirs,
- ProgressNotifier* progressNotifier)
- {
- // Say we're not ready to render yet.
- // bReady = false;
- #ifdef REQUIRE_LICENSE_FILE
- // Check for the presence of the license file--don't run unless it's there.
- {
- ifstream license("License.txt");
- if (!license.good())
- {
- fatalError(_("License file 'License.txt' is missing!"));
- return false;
- }
- }
- #endif
- if (configFileName != NULL)
- {
- config = ReadCelestiaConfig(*configFileName);
- }
- else
- {
- config = ReadCelestiaConfig("celestia.cfg");
- string localConfigFile = WordExp("~/.celestia.cfg");
- if (localConfigFile != "")
- ReadCelestiaConfig(localConfigFile.c_str(), config);
- }
- if (config == NULL)
- {
- fatalError(_("Error reading configuration file."));
- return false;
- }
- // Set the console log size; ignore any request to use less than 100 lines
- if (config->consoleLogRows > 100)
- console.setRowCount(config->consoleLogRows);
- #ifdef USE_SPICE
- if (!InitializeSpice())
- {
- fatalError(_("Initialization of SPICE library failed."));
- return false;
- }
- #endif
- // Insert additional extras directories into the configuration. These
- // additional directories typically come from the command line. It may
- // be useful to permit other command line overrides of config file fields.
- if (extrasDirs != NULL)
- {
- // Only insert the additional extras directories that aren't also
- // listed in the configuration file. The additional directories are added
- // after the ones from the config file and the order in which they were
- // specified is preserved. This process in O(N*M), but the number of
- // additional extras directories should be small.
- for (vector<string>::const_iterator iter = extrasDirs->begin();
- iter != extrasDirs->end(); iter++)
- {
- if (find(config->extrasDirs.begin(), config->extrasDirs.end(), *iter) ==
- config->extrasDirs.end())
- {
- config->extrasDirs.push_back(*iter);
- }
- }
- }
- #ifdef CELX
- initLuaHook(progressNotifier);
- #endif
- KeyRotationAccel = degToRad(config->rotateAcceleration);
- MouseRotationSensitivity = degToRad(config->mouseRotationSensitivity);
- readFavoritesFile();
- // If we couldn't read the favorites list from a file, allocate
- // an empty list.
- if (favorites == NULL)
- favorites = new FavoritesList();
- universe = new Universe();
- /***** Load star catalogs *****/
- if (!readStars(*config, progressNotifier))
- {
- fatalError(_("Cannot read star database."));
- return false;
- }
- /***** Load the deep sky catalogs *****/
- DSONameDatabase* dsoNameDB = new DSONameDatabase;
- DSODatabase* dsoDB = new DSODatabase;
- dsoDB->setNameDatabase(dsoNameDB);
-
- // Load first the vector of dsoCatalogFiles in the data directory (deepsky.dsc, globulars.dsc,...):
-
- for (vector<string>::const_iterator iter = config->dsoCatalogFiles.begin();
- iter != config->dsoCatalogFiles.end(); iter++)
- {
- if (progressNotifier)
- progressNotifier->update(*iter);
-
- ifstream dsoFile(iter->c_str(), ios::in);
- if (!dsoFile.good())
- {
- cerr<< _("Error opening deepsky catalog file.") << 'n';
- delete dsoDB;
- return false;
- }
- else if (!dsoDB->load(dsoFile, ""))
- {
- cerr << "Cannot read Deep Sky Objects database." << 'n';
- delete dsoDB;
- return false;
- }
- }
- // Next, read all the deep sky files in the extras directories
- {
- for (vector<string>::const_iterator iter = config->extrasDirs.begin();
- iter != config->extrasDirs.end(); iter++)
- {
- if (*iter != "")
- {
- Directory* dir = OpenDirectory(*iter);
- DeepSkyLoader loader(dsoDB,
- "deep sky object",
- Content_CelestiaDeepSkyCatalog,
- progressNotifier);
- loader.pushDir(*iter);
- dir->enumFiles(loader, true);
- delete dir;
- }
- }
- }
- dsoDB->finish();
- universe->setDSOCatalog(dsoDB);
- /***** Load the solar system catalogs *****/
- // First read the solar system files listed individually in the
- // config file.
- {
- SolarSystemCatalog* solarSystemCatalog = new SolarSystemCatalog();
- universe->setSolarSystemCatalog(solarSystemCatalog);
- for (vector<string>::const_iterator iter = config->solarSystemFiles.begin();
- iter != config->solarSystemFiles.end();
- iter++)
- {
- if (progressNotifier)
- progressNotifier->update(*iter);
- ifstream solarSysFile(iter->c_str(), ios::in);
- if (!solarSysFile.good())
- {
- warning(_("Error opening solar system catalog.n"));
- }
- else
- {
- LoadSolarSystemObjects(solarSysFile, *universe, "");
- }
- }
- }
- // Next, read all the solar system files in the extras directories
- {
- for (vector<string>::const_iterator iter = config->extrasDirs.begin();
- iter != config->extrasDirs.end(); iter++)
- {
- if (*iter != "")
- {
- Directory* dir = OpenDirectory(*iter);
- SolarSystemLoader loader(universe, progressNotifier);
- loader.pushDir(*iter);
- dir->enumFiles(loader, true);
- delete dir;
- }
- }
- }
- // Load asterisms:
- if (config->asterismsFile != "")
- {
- ifstream asterismsFile(config->asterismsFile.c_str(), ios::in);
- if (!asterismsFile.good())
- {
- warning(_("Error opening asterisms file."));
- }
- else
- {
- AsterismList* asterisms = ReadAsterismList(asterismsFile,
- *universe->getStarCatalog());
- universe->setAsterisms(asterisms);
- }
- }
- if (config->boundariesFile != "")
- {
- ifstream boundariesFile(config->boundariesFile.c_str(), ios::in);
- if (!boundariesFile.good())
- {
- warning(_("Error opening constellation boundaries files."));
- }
- else
- {
- ConstellationBoundaries* boundaries = ReadBoundaries(boundariesFile);
- universe->setBoundaries(boundaries);
- }
- }
- // Load destinations list
- if (config->destinationsFile != "")
- {
- string localeDestinationsFile = LocaleFilename(config->destinationsFile);
- ifstream destfile(localeDestinationsFile.c_str());
- if (destfile.good())
- {
- destinations = ReadDestinationList(destfile);
- }
- }
- sim = new Simulation(universe);
- if((renderer->getRenderFlags() & Renderer::ShowAutoMag) == 0)
- sim->setFaintestVisible(config->faintestVisible);
- View* view = new View(View::ViewWindow, sim->getActiveObserver(), 0.0f, 0.0f, 1.0f, 1.0f);
- views.insert(views.end(), view);
- activeView = views.begin();
- if (!compareIgnoringCase(getConfig()->cursor, "inverting crosshair"))
- {
- defaultCursorShape = CelestiaCore::InvertedCrossCursor;
- }
- if (!compareIgnoringCase(getConfig()->cursor, "arrow"))
- {
- defaultCursorShape = CelestiaCore::ArrowCursor;
- }
- if (cursorHandler != NULL)
- {
- cursorHandler->setCursorShape(defaultCursorShape);
- }
- return true;
- }
- bool CelestiaCore::initRenderer()
- {
- renderer->setRenderFlags(Renderer::ShowStars |
- Renderer::ShowPlanets |
- Renderer::ShowAtmospheres |
- Renderer::ShowAutoMag);
- GLContext* context = new GLContext();
- assert(context != NULL);
- if (context == NULL)
- return false;
- context->init(config->ignoreGLExtensions);
- // Choose the render path, starting with the least desirable
- context->setRenderPath(GLContext::GLPath_Basic);
- context->setRenderPath(GLContext::GLPath_Multitexture);
- context->setRenderPath(GLContext::GLPath_DOT3_ARBVP);
- context->setRenderPath(GLContext::GLPath_NvCombiner_NvVP);
- context->setRenderPath(GLContext::GLPath_NvCombiner_ARBVP);
- context->setRenderPath(GLContext::GLPath_GLSL);
- cout << _("render path: ") << context->getRenderPath() << 'n';
- Renderer::DetailOptions detailOptions;
- detailOptions.ringSystemSections = config->ringSystemSections;
- detailOptions.orbitPathSamplePoints = config->orbitPathSamplePoints;
- detailOptions.shadowTextureSize = config->shadowTextureSize;
- detailOptions.eclipseTextureSize = config->eclipseTextureSize;
- // Prepare the scene for rendering.
- if (!renderer->init(context, (int) width, (int) height, detailOptions))
- {
- fatalError(_("Failed to initialize renderer"));
- return false;
- }
- if ((renderer->getRenderFlags() & Renderer::ShowAutoMag) != 0)
- {
- renderer->setFaintestAM45deg(renderer->getFaintestAM45deg());
- setFaintestAutoMag();
- }
- if (config->mainFont == "")
- font = LoadTextureFont("fonts/default.txf");
- else
- font = LoadTextureFont(string("fonts/") + config->mainFont);
- if (font == NULL)
- {
- cout << _("Error loading font; text will not be visible.n");
- }
- else
- {
- font->buildTexture();
- }
- if (config->titleFont != "")
- titleFont = LoadTextureFont(string("fonts") + "/" + config->titleFont);
- if (titleFont != NULL)
- titleFont->buildTexture();
- else
- titleFont = font;
- // Set up the overlay
- overlay = new Overlay();
- overlay->setWindowSize(width, height);
- if (config->labelFont == "")
- {
- renderer->setFont(Renderer::FontNormal, font);
- }
- else
- {
- TextureFont* labelFont = LoadTextureFont(string("fonts") + "/" + config->labelFont);
- if (labelFont == NULL)
- {
- renderer->setFont(Renderer::FontNormal, font);
- }
- else
- {
- labelFont->buildTexture();
- renderer->setFont(Renderer::FontNormal, labelFont);
- }
- }
- renderer->setFont(Renderer::FontLarge, titleFont);
- if (config->logoTextureFile != "")
- {
- logoTexture = LoadTextureFromFile(string("textures") + "/" + config->logoTextureFile);
- }
- return true;
- }
- static void loadCrossIndex(StarDatabase* starDB,
- StarDatabase::Catalog catalog,
- const string& filename)
- {
- if (!filename.empty())
- {
- ifstream xrefFile(filename.c_str(), ios::in | ios::binary);
- if (xrefFile.good())
- {
- if (!starDB->loadCrossIndex(catalog, xrefFile))
- cerr << _("Error reading cross index ") << filename << 'n';
- else
- clog << _("Loaded cross index ") << filename << 'n';
- }
- }
- }
- bool CelestiaCore::readStars(const CelestiaConfig& cfg,
- ProgressNotifier* progressNotifier)
- {
- StarDetails::SetStarTextures(cfg.starTextures);
- ifstream starNamesFile(cfg.starNamesFile.c_str(), ios::in);
- if (!starNamesFile.good())
- {
- cerr << _("Error opening ") << cfg.starNamesFile << 'n';
- return false;
- }
- StarNameDatabase* starNameDB = StarNameDatabase::readNames(starNamesFile);
- if (starNameDB == NULL)
- {
- cerr << _("Error reading star names filen");
- return false;
- }
- // First load the binary star database file. The majority of stars
- // will be defined here.
- StarDatabase* starDB = new StarDatabase();
- if (!cfg.starDatabaseFile.empty())
- {
- if (progressNotifier)
- progressNotifier->update(cfg.starDatabaseFile);
- ifstream starFile(cfg.starDatabaseFile.c_str(), ios::in | ios::binary);
- if (!starFile.good())
- {
- cerr << _("Error opening ") << cfg.starDatabaseFile << 'n';
- delete starDB;
- return false;
- }
- if (!starDB->loadBinary(starFile))
- {
- delete starDB;
- cerr << _("Error reading stars filen");
- return false;
- }
- }
- starDB->setNameDatabase(starNameDB);
- loadCrossIndex(starDB, StarDatabase::HenryDraper, cfg.HDCrossIndexFile);
- loadCrossIndex(starDB, StarDatabase::SAO, cfg.SAOCrossIndexFile);
- loadCrossIndex(starDB, StarDatabase::Gliese, cfg.GlieseCrossIndexFile);
- // Next, read any ASCII star catalog files specified in the StarCatalogs
- // list.
- if (!cfg.starCatalogFiles.empty())
- {
- for (vector<string>::const_iterator iter = config->starCatalogFiles.begin();
- iter != config->starCatalogFiles.end(); iter++)
- {
- if (*iter != "")
- {
- ifstream starFile(iter->c_str(), ios::in);
- if (starFile.good())
- {
- starDB->load(starFile, "");
- }
- else
- {
- cerr << _("Error opening star catalog ") << *iter << 'n';
- }
- }
- }
- }
- // Now, read supplemental star files from the extras directories
- for (vector<string>::const_iterator iter = config->extrasDirs.begin();
- iter != config->extrasDirs.end(); iter++)
- {
- if (*iter != "")
- {
- Directory* dir = OpenDirectory(*iter);
- StarLoader loader(starDB, "star", Content_CelestiaStarCatalog, progressNotifier);
- loader.pushDir(*iter);
- dir->enumFiles(loader, true);
- delete dir;
- }
- }
- starDB->finish();
- universe->setStarCatalog(starDB);
- return true;
- }
- /// Set the faintest visible star magnitude; adjust the renderer's
- /// brightness parameters appropriately.
- void CelestiaCore::setFaintest(float magnitude)
- {
- sim->setFaintestVisible(magnitude);
- }
- /// Set faintest visible star magnitude and saturation magnitude
- /// for a given field of view;
- /// adjust the renderer's brightness parameters appropriately.
- void CelestiaCore::setFaintestAutoMag()
- {
- float faintestMag;
- renderer->autoMag(faintestMag);
- sim->setFaintestVisible(faintestMag);
- }
- void CelestiaCore::fatalError(const string& msg)
- {
- if (alerter == NULL)
- cout << msg;
- else
- alerter->fatalError(msg);
- }
- void CelestiaCore::setAlerter(Alerter* a)
- {
- alerter = a;
- }
- CelestiaCore::Alerter* CelestiaCore::getAlerter() const
- {
- return alerter;
- }
- /// Sets the cursor handler object.
- /// This must be set before calling initSimulation
- /// or the default cursor will not be used.
- void CelestiaCore::setCursorHandler(CursorHandler* handler)
- {
- cursorHandler = handler;
- }
- CelestiaCore::CursorHandler* CelestiaCore::getCursorHandler() const
- {
- return cursorHandler;
- }
- int CelestiaCore::getTimeZoneBias() const
- {
- return timeZoneBias;
- }
- bool CelestiaCore::getLightDelayActive() const
- {
- return lightTravelFlag;
- }
- void CelestiaCore::setLightDelayActive(bool lightDelayActive)
- {
- lightTravelFlag = lightDelayActive;
- }
- void CelestiaCore::setTextEnterMode(int mode)
- {
- if (mode != textEnterMode)
- {
- if ((mode & KbAutoComplete) != (textEnterMode & KbAutoComplete))
- {
- typedText = "";
- typedTextCompletion.clear();
- typedTextCompletionIdx = -1;
- }
- textEnterMode = mode;
- notifyWatchers(TextEnterModeChanged);
- }
- }
- int CelestiaCore::getTextEnterMode() const
- {
- return textEnterMode;
- }
- void CelestiaCore::setScreenDpi(int dpi)
- {
- screenDpi = dpi;
- setFOVFromZoom();
- renderer->setScreenDpi(dpi);
- }
- int CelestiaCore::getScreenDpi() const
- {
- return screenDpi;
- }
- void CelestiaCore::setDistanceToScreen(int dts)
- {
- distanceToScreen = dts;
- setFOVFromZoom();
- }
- int CelestiaCore::getDistanceToScreen() const
- {
- return distanceToScreen;
- }
- void CelestiaCore::setTimeZoneBias(int bias)
- {
- timeZoneBias = bias;
- notifyWatchers(TimeZoneChanged);
- }
- string CelestiaCore::getTimeZoneName() const
- {
- return timeZoneName;
- }
- void CelestiaCore::setTimeZoneName(const string& zone)
- {
- timeZoneName = zone;
- }
- int CelestiaCore::getHudDetail()
- {
- return hudDetail;
- }
- void CelestiaCore::setHudDetail(int newHudDetail)
- {
- hudDetail = newHudDetail%3;
- notifyWatchers(VerbosityLevelChanged);
- }
- astro::Date::Format CelestiaCore::getDateFormat() const
- {
- return dateFormat;
- }
- void CelestiaCore::setDateFormat(astro::Date::Format format)
- {
- dateStrWidth = 0;
- dateFormat = format;
- }
- int CelestiaCore::getOverlayElements() const
- {
- return overlayElements;
- }
- void CelestiaCore::setOverlayElements(int _overlayElements)
- {
- overlayElements = _overlayElements;
- }
- void CelestiaCore::initMovieCapture(MovieCapture* mc)
- {
- if (movieCapture == NULL)
- movieCapture = mc;
- }
- void CelestiaCore::recordBegin()
- {
- if (movieCapture != NULL) {
- recording = true;
- movieCapture->recordingStatus(true);
- }
- }
- void CelestiaCore::recordPause()
- {
- recording = false;
- if (movieCapture != NULL) movieCapture->recordingStatus(false);
- }
- void CelestiaCore::recordEnd()
- {
- if (movieCapture != NULL)
- {
- recordPause();
- movieCapture->end();
- delete movieCapture;
- movieCapture = NULL;
- }
- }
- bool CelestiaCore::isCaptureActive()
- {
- return movieCapture != NULL;
- }
- bool CelestiaCore::isRecording()
- {
- return recording;
- }
- void CelestiaCore::flash(const string& s, double duration)
- {
- if (hudDetail > 0)
- showText(s, -1, -1, 0, 5, duration);
- }
- CelestiaConfig* CelestiaCore::getConfig() const
- {
- return config;
- }
- void CelestiaCore::addWatcher(CelestiaWatcher* watcher)
- {
- assert(watcher != NULL);
- watchers.insert(watchers.end(), watcher);
- }
- void CelestiaCore::removeWatcher(CelestiaWatcher* watcher)
- {
- vector<CelestiaWatcher*>::iterator iter =
- find(watchers.begin(), watchers.end(), watcher);
- if (iter != watchers.end())
- watchers.erase(iter);
- }
- void CelestiaCore::notifyWatchers(int property)
- {
- for (vector<CelestiaWatcher*>::iterator iter = watchers.begin();
- iter != watchers.end(); iter++)
- {
- (*iter)->notifyChange(this, property);
- }
- }
- void CelestiaCore::goToUrl(const string& urlStr)
- {
- Url url(urlStr, this);
- url.goTo();
- notifyWatchers(RenderFlagsChanged | LabelFlagsChanged);
- }
- void CelestiaCore::addToHistory()
- {
- Url url(this);
- if (!history.empty() && historyCurrent < history.size() - 1)
- {
- // truncating history to current position
- while (historyCurrent != history.size() - 1)
- {
- history.pop_back();
- }
- }
- history.push_back(url);
- historyCurrent = history.size() - 1;
- notifyWatchers(HistoryChanged);
- }
- void CelestiaCore::back()
- {
- if (historyCurrent == 0) return;
- if (historyCurrent == history.size() - 1)
- {
- addToHistory();
- historyCurrent = history.size()-1;
- }
- historyCurrent--;
- history[historyCurrent].goTo();
- notifyWatchers(HistoryChanged|RenderFlagsChanged|LabelFlagsChanged);
- }
- void CelestiaCore::forward()
- {
- if (history.size() == 0) return;
- if (historyCurrent == history.size()-1) return;
- historyCurrent++;
- history[historyCurrent].goTo();
- notifyWatchers(HistoryChanged|RenderFlagsChanged|LabelFlagsChanged);
- }
- const vector<Url>& CelestiaCore::getHistory() const
- {
- return history;
- }
- vector<Url>::size_type CelestiaCore::getHistoryCurrent() const
- {
- return historyCurrent;
- }
- void CelestiaCore::setHistoryCurrent(vector<Url>::size_type curr)
- {
- if (curr >= history.size()) return;
- if (historyCurrent == history.size()) {
- addToHistory();
- }
- historyCurrent = curr;
- history[curr].goTo();
- notifyWatchers(HistoryChanged|RenderFlagsChanged|LabelFlagsChanged);
- }
- /*! Toggle the specified reference mark for a selection.
- * a selection. The default value for the selection argument is
- * the current simulation selection. This method does nothing
- * if the selection isn't a solar system body.
- */
- void CelestiaCore::toggleReferenceMark(const string& refMark, Selection sel)
- {
- Body* body = NULL;
- if (sel.empty())
- body = getSimulation()->getSelection().body();
- else
- body = sel.body();
-
- // Reference marks can only be set for solar system bodies.
- if (body == NULL)
- return;
- if (body->findReferenceMark(refMark))
- {
- body->removeReferenceMark(refMark);
- }
- else
- {
- if (refMark == "body axes")
- {
- body->addReferenceMark(new BodyAxisArrows(*body));
- }
- else if (refMark == "frame axes")
- {
- body->addReferenceMark(new FrameAxisArrows(*body));
- }
- else if (refMark == "sun direction")
- {
- body->addReferenceMark(new SunDirectionArrow(*body));
- }
- else if (refMark == "velocity vector")
- {
- body->addReferenceMark(new VelocityVectorArrow(*body));
- }
- else if (refMark == "spin vector")
- {
- body->addReferenceMark(new SpinVectorArrow(*body));
- }
- else if (refMark == "frame center direction")
- {
- double now = getSimulation()->getTime();
- BodyToBodyDirectionArrow* arrow = new BodyToBodyDirectionArrow(*body, body->getOrbitFrame(now)->getCenter());
- arrow->setTag(refMark);
- body->addReferenceMark(arrow);
- }
- else if (refMark == "planetographic grid")
- {
- body->addReferenceMark(new PlanetographicGrid(*body));
- }
- else if (refMark == "terminator")
- {
- double now = getSimulation()->getTime();
- Star* sun = NULL;
- Body* b = body;
- while (b != NULL)
- {
- Selection center = b->getOrbitFrame(now)->getCenter();
- if (center.star() != NULL)
- sun = center.star();
- b = center.body();
- }
- if (sun != NULL)
- {
- VisibleRegion* visibleRegion = new VisibleRegion(*body, Selection(sun));
- visibleRegion->setTag("terminator");
- body->addReferenceMark(visibleRegion);
- }
- }
- }
- }
- /*! Return whether the specified reference mark is enabled for a
- * a selection. The default value for the selection argument is
- * the current simulation selection.
- */
- bool CelestiaCore::referenceMarkEnabled(const string& refMark, Selection sel) const
- {
- Body* body = NULL;
- if (sel.empty())
- body = getSimulation()->getSelection().body();
- else
- body = sel.body();
-
- // Reference marks can only be set for solar system bodies.
- if (body == NULL)
- return false;
- else
- return body->findReferenceMark(refMark) != NULL;
- }
- #ifdef CELX
- class LuaPathFinder : public EnumFilesHandler
- {
- public:
- string luaPath;
- LuaPathFinder(string s) : luaPath(s) {};
- string lastPath;
- bool process(const string& filename)
- {
- if (getPath() != lastPath)
- {
- int extPos = filename.rfind('.');
- if (extPos != (int)string::npos)
- {
- string ext = string(filename, extPos, filename.length() - extPos + 1);
- if (ext == ".lua")
- {
- lastPath = getPath();
- string newPatt = getPath()+"/?.lua;";
- extPos = luaPath.rfind(newPatt);
- if (extPos < 0)
- {
- luaPath = luaPath + newPatt;
- }
- }
- }
- }
- return true;
- };
- };
- // Initialize the Lua hook table as well as the Lua state for scripted
- // objects. The Lua hook operates in a different Lua state than user loaded
- // scripts. It always has file system access via the IO package. If the script
- // system access policy is "allow", then scripted objects will run in the same
- // Lua context as the Lua hook. Sharing state between scripted objects and the
- // hook can be very useful, but it gives system access to scripted objects,
- // and therefore must be restricted based on the system access policy.
- bool CelestiaCore::initLuaHook(ProgressNotifier* progressNotifier)
- {
- luaHook = new LuaState();
- luaHook->init(this);
- string LuaPath = "?.lua;celxx/?.lua;";
- // Find the path for lua files in the extras directories
- {
- for (vector<string>::const_iterator iter = config->extrasDirs.begin();
- iter != config->extrasDirs.end(); iter++)
- {
- if (*iter != "")
- {
- Directory* dir = OpenDirectory(*iter);
- LuaPathFinder loader("");
- loader.pushDir(*iter);
- dir->enumFiles(loader, true);
- LuaPath += loader.luaPath;
- delete dir;
- }
- }
- }
- // Always grant access for the Lua hook
- luaHook->allowSystemAccess();
- luaHook->setLuaPath(LuaPath);
- int status = 0;
- // Execute the Lua hook initialization script
- if (config->luaHook != "")
- {
- string filename = config->luaHook;
- ifstream scriptfile(filename.c_str());
- if (!scriptfile.good())
- {
- char errMsg[1024];
- sprintf(errMsg, "Error opening LuaHook '%s'", filename.c_str());
- if (alerter != NULL)
- alerter->fatalError(errMsg);
- else
- flash(errMsg);
- }
- if (progressNotifier)
- progressNotifier->update(config->luaHook);
- status = luaHook->loadScript(scriptfile, filename);
- }
- else
- {
- status = luaHook->loadScript("");
- }
- if (status != 0)
- {
- cout << "lua hook load failedn";
- string errMsg = luaHook->getErrorMessage();
- if (errMsg.empty())
- errMsg = "Unknown error loading hook script";
- if (alerter != NULL)
- alerter->fatalError(errMsg);
- else
- flash(errMsg);
- delete luaHook;
- luaHook = NULL;
- }
- else
- {
- // Coroutine execution; control may be transferred between the
- // script and Celestia's event loop
- if (!luaHook->createThread())
- {
- const char* errMsg = "Script coroutine initialization failed";
- cout << "hook thread failedn";
- if (alerter != NULL)
- alerter->fatalError(errMsg);
- else
- flash(errMsg);
- delete luaHook;
- luaHook = NULL;
- }
- if (luaHook)
- {
- while (!luaHook->tick(0.1)) ;
- }
- }
- // Set up the script context; if the system access policy is allow,
- // it will share the same context as the Lua hook. Otherwise, we
- // create a private context.
- if (config->scriptSystemAccessPolicy == "allow")
- {
- SetScriptedObjectContext(luaHook->getState());
- }
- else
- {
- luaSandbox = new LuaState();
- luaSandbox->init(this);
- // Allow access to functions in package because we need 'require'
- // But, loadlib is prohibited.
- luaSandbox->allowLuaPackageAccess();
- luaSandbox->setLuaPath(LuaPath);
- status = luaSandbox->loadScript("");
- if (status != 0)
- {
- delete luaSandbox;
- luaSandbox = NULL;
- }
- SetScriptedObjectContext(luaSandbox->getState());
- }
- return true;
- }
- #endif