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

solarsys.cpp File Reference

#include <cassert>
#include <cstdio>
#include <config.h>
#include <celutil/debug.h>
#include <celmath/mathlib.h>
#include <celutil/util.h>
#include "astro.h"
#include "parser.h"
#include "texmanager.h"
#include "meshmanager.h"
#include "universe.h"
#include "multitexture.h"
#include "parseobject.h"

Include dependency graph for solarsys.cpp:

Go to the source code of this file.

Enumerations

enum  Disposition { AddObject, ReplaceObject, ModifyObject }

Functions

static LocationCreateLocation (Hash *locationData, Body *body)
static BodyCreatePlanet (PlanetarySystem *system, Body *existingBody, Hash *planetData, const string &path, Disposition disposition, bool usePlanetUnits=true)
static void errorMessagePrelude (const Tokenizer &tok)
static void FillinSurface (Hash *surfaceData, Surface *surface, const std::string &path)
bool LoadSolarSystemObjects (istream &in, Universe &universe, const std::string &directory)
static void sscError (const Tokenizer &tok, const string &msg)


Enumeration Type Documentation

enum Disposition
 

Enumeration values:
AddObject 
ReplaceObject 
ModifyObject 

Definition at line 37 of file solarsys.cpp.

00038 {
00039     AddObject,
00040     ReplaceObject,
00041     ModifyObject,
00042 };


Function Documentation

static Location* CreateLocation Hash locationData,
Body body
[static]
 

Definition at line 91 of file solarsys.cpp.

References Location::setFeatureType(), Location::setImportance(), Location::setPosition(), Location::setSize(), Vector3< T >::x, Vector3< T >::y, and Vector3< T >::z.

Referenced by LoadSolarSystemObjects().

00093 {
00094     Location* location = new Location();
00095 
00096     Vec3d longlat(0.0, 0.0, 0.0);
00097     locationData->getVector("LongLat", longlat);
00098 
00099     Vec3f position = body->planetocentricToCartesian((float) longlat.x,
00100                                                      (float) longlat.y,
00101                                                      (float) longlat.z);
00102     location->setPosition(position);
00103 
00104     double size = 1.0;
00105     locationData->getNumber("Size", size);
00106     location->setSize((float) size);
00107 
00108     double importance = -1.0;
00109     locationData->getNumber("Importance", importance);
00110     location->setImportance((float) importance);
00111 
00112     string featureTypeName;
00113     if (locationData->getString("Type", featureTypeName))
00114         location->setFeatureType(Location::parseFeatureType(featureTypeName));
00115 
00116     return location;
00117 }

static Body* CreatePlanet PlanetarySystem system,
Body existingBody,
Hash planetData,
const string path,
Disposition  disposition,
bool  usePlanetUnits = true
[static]
 

Definition at line 209 of file solarsys.cpp.

References Atmosphere::cloudHeight, Atmosphere::cloudSpeed, Atmosphere::cloudTexture, RingSystem::color, Surface::color, compareIgnoringCase(), CreateOrbit(), degToRad(), DPRINTF, FillinRotationElements(), FillinSurface(), Body::getAtmosphere(), Body::getClassification(), AssociativeArray::getColor(), ResourceManager< T >::getHandle(), Value::getHash(), Body::getLifespan(), GetModelManager(), Body::getName(), AssociativeArray::getNumber(), Body::getOrbit(), Orbit::getPeriod(), Body::getRadius(), Body::getRings(), Body::getRotationElements(), AssociativeArray::getString(), Body::getSurface(), Value::getType(), Surface::hazeColor, Atmosphere::height, RingSystem::innerRadius, Atmosphere::lowerColor, ModifyObject, RingSystem::outerRadius, ParseDate(), RotationElements::period, Body::setAlbedo(), Body::setAtmosphere(), Body::setClassification(), Body::setInfoURL(), Body::setLifespan(), Body::setMass(), Body::setModel(), Body::setOblateness(), Body::setOrbit(), Body::setOrientation(), Body::setRadius(), Body::setRings(), Body::setRotationElements(), Body::setSurface(), MultiResTexture::setTexture(), Atmosphere::skyColor, Atmosphere::sunsetColor, RingSystem::texture, and Atmosphere::upperColor.

Referenced by LoadSolarSystemObjects().

00215 {
00216     Body* body = NULL;
00217   
00218     if (disposition == ModifyObject)
00219     {
00220         body = existingBody;
00221     }
00222 
00223     if (body == NULL)
00224     {
00225         body = new Body(system);
00226     }
00227 
00228     Orbit* orbit = CreateOrbit(system, planetData, path, usePlanetUnits);
00229 
00230     if (orbit != NULL)
00231     {
00232         body->setOrbit(orbit);
00233     }
00234 
00235     if (body->getOrbit() == NULL)
00236     {
00237         DPRINTF(0, "No valid orbit specified for object '%s'; skipping . . .\n",
00238                 body->getName().c_str());
00239         delete body;
00240         return NULL;
00241     }
00242 
00243     double radius = (double)body->getRadius();
00244     planetData->getNumber("Radius", radius);
00245     body->setRadius((float) radius);
00246 
00247     int classification = body->getClassification();
00248     string classificationName;
00249     if (planetData->getString("Class", classificationName))
00250     {
00251         if (compareIgnoringCase(classificationName, "planet") == 0)
00252             classification = Body::Planet;
00253         else if (compareIgnoringCase(classificationName, "moon") == 0)
00254             classification = Body::Moon;
00255         else if (compareIgnoringCase(classificationName, "comet") == 0)
00256             classification = Body::Comet;
00257         else if (compareIgnoringCase(classificationName, "asteroid") == 0)
00258             classification = Body::Asteroid;
00259         else if (compareIgnoringCase(classificationName, "spacecraft") == 0)
00260             classification = Body::Spacecraft;
00261         else if (compareIgnoringCase(classificationName, "invisible") == 0)
00262             classification = Body::Invisible;
00263     }
00264 
00265     if (classification == Body::Unknown)
00266     {
00267         //Try to guess the type
00268         if (system->getPrimaryBody() != NULL)
00269         {
00270             if(radius > 0.1)
00271                 classification = Body::Moon;
00272             else
00273                 classification = Body::Spacecraft;
00274         }
00275         else
00276         {
00277             if(radius < 1000.0)
00278                 classification = Body::Asteroid;
00279             else
00280                 classification = Body::Planet;
00281         }
00282     }
00283     body->setClassification(classification);
00284 
00285     // g++ is missing limits header, so we can use this
00286     // double beginning   = -numeric_limits<double>::infinity();
00287     // double ending      =  numeric_limits<double>::infinity();
00288     double beginning   = -1.0e+50;
00289     double ending      =  1.0e+50;
00290     body->getLifespan(beginning, ending);
00291     ParseDate(planetData, "Beginning", beginning);
00292     ParseDate(planetData, "Ending", ending);
00293     body->setLifespan(beginning, ending);
00294 
00295     string infoURL;
00296     if (planetData->getString("InfoURL", infoURL))
00297         body->setInfoURL(infoURL);
00298     
00299     double albedo = 0.5;
00300     if (planetData->getNumber("Albedo", albedo))
00301         body->setAlbedo((float) albedo);
00302 
00303     double oblateness = 0.0;
00304     if (planetData->getNumber("Oblateness", oblateness))
00305         body->setOblateness((float) oblateness);
00306     
00307     double mass = 0.0;
00308     if (planetData->getNumber("Mass", mass))
00309         body->setMass((float) mass);
00310 
00311     Quatf orientation;
00312     if (planetData->getRotation("Orientation", orientation))
00313         body->setOrientation(orientation);
00314 
00315     RotationElements re = body->getRotationElements();
00316     if (disposition != ModifyObject)
00317         re.period = (float) body->getOrbit()->getPeriod();
00318     FillinRotationElements(planetData, re);
00319     body->setRotationElements(re);
00320 
00321     Surface surface;
00322     if (disposition == ModifyObject)
00323     {
00324         surface = body->getSurface();
00325     }
00326     else
00327     {
00328         surface.color = Color(1.0f, 1.0f, 1.0f);
00329         surface.hazeColor = Color(0.0f, 0.0f, 0.0f, 0.0f);
00330     }
00331     FillinSurface(planetData, &surface, path);
00332     body->setSurface(surface);
00333 
00334     {
00335         string model("");
00336         if (planetData->getString("Mesh", model))
00337         {
00338             Vec3f modelCenter(0.0f, 0.0f, 0.0f);
00339             if (planetData->getVector("MeshCenter", modelCenter))
00340             {
00341                 // TODO: Adjust bounding radius if model center isn't
00342                 // (0.0f, 0.0f, 0.0f)
00343             }
00344 
00345             ResourceHandle modelHandle = GetModelManager()->getHandle(ModelInfo(model, path, modelCenter));
00346             body->setModel(modelHandle);
00347 
00348         }
00349     }
00350 
00351     // Read the atmosphere
00352     {
00353         Value* atmosDataValue = planetData->getValue("Atmosphere");
00354         if (atmosDataValue != NULL)
00355         {
00356             if (atmosDataValue->getType() != Value::HashType)
00357             {
00358                 cout << "ReadSolarSystem: Atmosphere must be an assoc array.\n";
00359             }
00360             else
00361             {
00362                 Hash* atmosData = atmosDataValue->getHash();
00363                 assert(atmosData != NULL);
00364                 
00365                 Atmosphere* atmosphere = NULL;
00366                 if (disposition == ModifyObject)
00367                 {
00368                     atmosphere = body->getAtmosphere();
00369                     if (atmosphere == NULL)
00370                     {
00371                         Atmosphere atm;
00372                         body->setAtmosphere(atm);
00373                         atmosphere = body->getAtmosphere();
00374                     }
00375                 }
00376                 else
00377                 {
00378                     atmosphere = new Atmosphere();
00379                 }
00380                 atmosData->getNumber("Height", atmosphere->height);
00381                 atmosData->getColor("Lower", atmosphere->lowerColor);
00382                 atmosData->getColor("Upper", atmosphere->upperColor);
00383                 atmosData->getColor("Sky", atmosphere->skyColor);
00384                 atmosData->getColor("Sunset", atmosphere->sunsetColor);
00385                 atmosData->getNumber("CloudHeight", atmosphere->cloudHeight);
00386                 if (atmosData->getNumber("CloudSpeed", atmosphere->cloudSpeed))
00387                     atmosphere->cloudSpeed = degToRad(atmosphere->cloudSpeed);
00388 
00389                 string cloudTexture;
00390                 if (atmosData->getString("CloudMap", cloudTexture))
00391                 {
00392                     atmosphere->cloudTexture.setTexture(cloudTexture,
00393                                                         path,
00394                                                         TextureInfo::WrapTexture);
00395                 }
00396 
00397                 body->setAtmosphere(*atmosphere);
00398                 if (disposition != ModifyObject)
00399                     delete atmosphere;
00400             }
00401 
00402             delete atmosDataValue;
00403         }
00404     }
00405 
00406     // Read the ring system
00407     {
00408         Value* ringsDataValue = planetData->getValue("Rings");
00409         if (ringsDataValue != NULL)
00410         {
00411             if (ringsDataValue->getType() != Value::HashType)
00412             {
00413                 cout << "ReadSolarSystem: Rings must be an assoc array.\n";
00414             }
00415             else
00416             {
00417                 Hash* ringsData = ringsDataValue->getHash();
00418                 // ASSERT(ringsData != NULL);
00419 
00420                 RingSystem rings(0.0f, 0.0f);
00421                 if (body->getRings() != NULL)
00422                     rings = *body->getRings();
00423 
00424                 double inner = 0.0, outer = 0.0;
00425                 if (ringsData->getNumber("Inner", inner))
00426                     rings.innerRadius = (float) inner;
00427                 if (ringsData->getNumber("Outer", outer))
00428                     rings.outerRadius = (float) outer;
00429 
00430                 Color color(1.0f, 1.0f, 1.0f);
00431                 if (ringsData->getColor("Color", color))
00432                     rings.color = color;
00433 
00434                 string textureName;
00435                 if (ringsData->getString("Texture", textureName))
00436                     rings.texture = MultiResTexture(textureName, path);
00437 
00438                 body->setRings(rings);
00439             }
00440 
00441             delete ringsDataValue;
00442         }
00443     }
00444 
00445     return body;
00446 }

static void errorMessagePrelude const Tokenizer tok  )  [static]
 

Solar system catalog (.ssc) files contain items of three different types: bodies, locations, and alternate surfaces. Bodies planets, moons, asteroids, comets, and spacecraft. Locations are points on the surfaces of bodies which may be labelled but aren't rendered. Alternate surfaces are additional surface definitions for bodies.

An ssc file contains zero or more definitions of this form:

  [disposition] [item type] "name" "parent name"
  {
     ...object info fields...
  }

The disposition of the object determines what happens if an item with the same parent and same name already exists. It may be one of the following:

  • Add - Default if none is specified. Add the item even if one of the same name already exists.
  • Replace - Replace an existing item with the new one
  • Modify - Modify the existing item, changing the fields that appear in the new definition.

All dispositions are equivalent to add if no item of the same name already exists.

The item type is one of Body, Location, or AltSurface, defaulting to Body when no type is given.

The name and parent name are both mandatory.

Definition at line 78 of file solarsys.cpp.

References _.

Referenced by LoadSolarSystemObjects(), sscError(), and stcError().

00079 {
00080     cerr << _("Error in .ssc file (line ") << tok.getLineNumber() << "): ";
00081 }

static void FillinSurface Hash surfaceData,
Surface surface,
const std::string path
[static]
 

Definition at line 120 of file solarsys.cpp.

References Color::alpha(), Color::blue(), Color::green(), and Color::red().

Referenced by CreatePlanet(), and LoadSolarSystemObjects().

00123 {
00124     surfaceData->getColor("Color", surface->color);
00125 
00126     Color hazeColor = surface->hazeColor;
00127     float hazeDensity = hazeColor.alpha();
00128     if (surfaceData->getColor("HazeColor", hazeColor) | surfaceData->getNumber("HazeDensity", hazeDensity))
00129     {
00130         surface->hazeColor = Color(hazeColor.red(), hazeColor.green(),
00131                                    hazeColor.blue(), hazeDensity);
00132     }
00133 
00134     surfaceData->getColor("SpecularColor", surface->specularColor);
00135     surfaceData->getNumber("SpecularPower", surface->specularPower);
00136 
00137     string baseTexture;
00138     string bumpTexture;
00139     string nightTexture;
00140     string specularTexture;
00141     string normalTexture;
00142     string overlayTexture;
00143     bool applyBaseTexture = surfaceData->getString("Texture", baseTexture);
00144     bool applyBumpMap = surfaceData->getString("BumpMap", bumpTexture);
00145     bool applyNightMap = surfaceData->getString("NightTexture", nightTexture);
00146     bool separateSpecular = surfaceData->getString("SpecularTexture",
00147                                                    specularTexture);
00148     bool applyNormalMap = surfaceData->getString("NormalMap", normalTexture);
00149     bool applyOverlay = surfaceData->getString("OverlayTexture",
00150                                                overlayTexture);
00151 
00152     unsigned int baseFlags = TextureInfo::WrapTexture | TextureInfo::AllowSplitting;
00153     unsigned int bumpFlags = TextureInfo::WrapTexture | TextureInfo::AllowSplitting;
00154     unsigned int nightFlags = TextureInfo::WrapTexture | TextureInfo::AllowSplitting;
00155     unsigned int specularFlags = TextureInfo::WrapTexture | TextureInfo::AllowSplitting;
00156     
00157     float bumpHeight = 2.5f;
00158     surfaceData->getNumber("BumpHeight", bumpHeight);
00159 
00160     bool blendTexture = false;
00161     surfaceData->getBoolean("BlendTexture", blendTexture);
00162 
00163     bool emissive = false;
00164     surfaceData->getBoolean("Emissive", emissive);
00165 
00166     bool compressTexture = false;
00167     surfaceData->getBoolean("CompressTexture", compressTexture);
00168     if (compressTexture)
00169         baseFlags |= TextureInfo::CompressTexture;
00170 
00171     if (blendTexture)
00172         surface->appearanceFlags |= Surface::BlendTexture;
00173     if (emissive)
00174         surface->appearanceFlags |= Surface::Emissive;
00175     if (applyBaseTexture)
00176         surface->appearanceFlags |= Surface::ApplyBaseTexture;
00177     if (applyBumpMap || applyNormalMap)
00178         surface->appearanceFlags |= Surface::ApplyBumpMap;
00179     if (applyNightMap)
00180         surface->appearanceFlags |= Surface::ApplyNightMap;
00181     if (separateSpecular)
00182         surface->appearanceFlags |= Surface::SeparateSpecularMap;
00183     if (applyOverlay)
00184         surface->appearanceFlags |= Surface::ApplyOverlay;
00185     if (surface->specularColor != Color(0.0f, 0.0f, 0.0f))
00186         surface->appearanceFlags |= Surface::SpecularReflection;
00187 
00188     if (applyBaseTexture)
00189         surface->baseTexture.setTexture(baseTexture, path, baseFlags);
00190     if (applyNightMap)
00191         surface->nightTexture.setTexture(nightTexture, path, nightFlags);
00192     if (separateSpecular)
00193         surface->specularTexture.setTexture(specularTexture, path, specularFlags);
00194 
00195     // If both are present, NormalMap overrides BumpMap
00196     if (applyNormalMap)
00197         surface->bumpTexture.setTexture(normalTexture, path, bumpFlags);
00198     else if (applyBumpMap)
00199         surface->bumpTexture.setTexture(bumpTexture, path, bumpHeight, bumpFlags);
00200 
00201     if (applyOverlay)
00202         surface->overlayTexture.setTexture(overlayTexture, path, baseFlags);
00203 }

bool LoadSolarSystemObjects istream &  in,
Universe universe,
const std::string directory
 

Definition at line 449 of file solarsys.cpp.

References _, Body::addAlternateSurface(), PlanetarySystem::addBody(), Body::addLocation(), AddObject, Selection::body(), Surface::color, CreateLocation(), CreatePlanet(), errorMessagePrelude(), FillinSurface(), PlanetarySystem::find(), Value::getHash(), Tokenizer::getNameValue(), SolarSystem::getPlanets(), Body::getSatellites(), Tokenizer::getStringValue(), Tokenizer::getTokenType(), Value::getType(), Surface::hazeColor, ModifyObject, Tokenizer::nextToken(), Parser::readValue(), PlanetarySystem::replaceBody(), ReplaceObject, Location::setName(), Body::setName(), Body::setSatellites(), sscError(), and Selection::star().

Referenced by CelestiaCore::initSimulation(), and SolarSystemLoader::process().

00452 {
00453     Tokenizer tokenizer(&in); 
00454     Parser parser(&tokenizer);
00455 
00456     while (tokenizer.nextToken() != Tokenizer::TokenEnd)
00457     {
00458         // Read the disposition; if none is specified, the default is Add.
00459         Disposition disposition = AddObject;
00460         if (tokenizer.getTokenType() == Tokenizer::TokenName)
00461         {
00462             if (tokenizer.getNameValue() == "Add")
00463             {
00464                 disposition = AddObject;
00465                 tokenizer.nextToken();
00466             }
00467             else if (tokenizer.getNameValue() == "Replace")
00468             {
00469                 disposition = ReplaceObject;
00470                 tokenizer.nextToken();
00471             }
00472             else if (tokenizer.getNameValue() == "Modify")
00473             {
00474                 disposition = ModifyObject;
00475                 tokenizer.nextToken();
00476             }
00477         }
00478 
00479         // Read the item type; if none is specified the default is Body
00480         string itemType("Body");
00481         if (tokenizer.getTokenType() == Tokenizer::TokenName)
00482         {
00483             itemType = tokenizer.getNameValue();
00484             tokenizer.nextToken();
00485         }
00486 
00487         if (tokenizer.getTokenType() != Tokenizer::TokenString)
00488         {
00489             sscError(tokenizer, "object name expected");
00490             return false;
00491         }
00492         string name = tokenizer.getStringValue().c_str();
00493 
00494         if (tokenizer.nextToken() != Tokenizer::TokenString)
00495         {
00496             sscError(tokenizer, "bad parent object name");
00497             return false;
00498         }
00499         string parentName = tokenizer.getStringValue().c_str();
00500 
00501         Value* objectDataValue = parser.readValue();
00502         if (objectDataValue == NULL)
00503         {
00504             sscError(tokenizer, "bad object definition");
00505             return false;
00506         }
00507 
00508         if (objectDataValue->getType() != Value::HashType)
00509         {
00510             sscError(tokenizer, "{ expected");
00511             return false;
00512         }
00513         Hash* objectData = objectDataValue->getHash();
00514 
00515         Selection parent = universe.findPath(parentName, NULL, 0);
00516         PlanetarySystem* parentSystem = NULL;
00517 
00518         if (itemType == "Body")
00519         {
00520             bool orbitsPlanet = false;
00521             if (parent.star() != NULL)
00522             {
00523                 SolarSystem* solarSystem = universe.getSolarSystem(parent.star());
00524                 if (solarSystem == NULL)
00525                 {
00526                     // No solar system defined for this star yet, so we need
00527                     // to create it.
00528                     solarSystem = universe.createSolarSystem(parent.star());
00529                 }
00530                 parentSystem = solarSystem->getPlanets();
00531             }
00532             else if (parent.body() != NULL)
00533             {
00534                 // Parent is a planet or moon
00535                 parentSystem = parent.body()->getSatellites();
00536                 if (parentSystem == NULL)
00537                 {
00538                     // If the planet doesn't already have any satellites, we
00539                     // have to create a new planetary system for it.
00540                     parentSystem = new PlanetarySystem(parent.body());
00541                     parent.body()->setSatellites(parentSystem);
00542                 }
00543                 orbitsPlanet = true;
00544             }
00545             else
00546             {
00547                 errorMessagePrelude(tokenizer);
00548                 cerr << _("parent body '") << parentName << _("' of '") << name << _("' not found.\n");
00549             }
00550 
00551             if (parentSystem != NULL)
00552             {
00553                 Body* existingBody = parentSystem->find(name);
00554                 if (existingBody && disposition == AddObject)
00555                 {
00556                     errorMessagePrelude(tokenizer);
00557                     cerr << _("warning duplicate definition of ") <<
00558                         parentName << " " <<  name << '\n';
00559                 }
00560                 
00561                 Body* body = CreatePlanet(parentSystem, existingBody, objectData, directory, disposition, !orbitsPlanet);
00562                 if (body != NULL)
00563                 {
00564                     body->setName(name);
00565                     if (disposition == ReplaceObject)
00566                     {
00567                         parentSystem->replaceBody(existingBody, body);
00568                         delete existingBody;
00569                     } 
00570                     else if (disposition == AddObject)
00571                     {
00572                         parentSystem->addBody(body);
00573                     }
00574                 }
00575             }
00576         }
00577         else if (itemType == "AltSurface")
00578         {
00579             Surface* surface = new Surface();
00580             surface->color = Color(1.0f, 1.0f, 1.0f);
00581             surface->hazeColor = Color(0.0f, 0.0f, 0.0f, 0.0f);
00582             FillinSurface(objectData, surface, directory);
00583             if (surface != NULL && parent.body() != NULL)
00584                 parent.body()->addAlternateSurface(name, surface);
00585             else
00586                 sscError(tokenizer, _("bad alternate surface"));
00587         }
00588         else if (itemType == "Location")
00589         {
00590             if (parent.body() != NULL)
00591             {
00592                 Location* location = CreateLocation(objectData, parent.body());
00593                 if (location != NULL)
00594                 {
00595                     location->setName(name);
00596                     parent.body()->addLocation(location);
00597                 }
00598                 else
00599                 {
00600                     sscError(tokenizer, _("bad location"));
00601                 }
00602             }
00603             else
00604             {
00605                 errorMessagePrelude(tokenizer);
00606                 cerr << _("parent body '") << parentName << _("' of '") << name << _("' not found.\n");
00607             }
00608         }
00609     }
00610 
00611     // TODO: Return some notification if there's an error parsing the file
00612     return true;
00613 }

static void sscError const Tokenizer tok,
const string msg
[static]
 

Definition at line 83 of file solarsys.cpp.

References errorMessagePrelude().

Referenced by LoadSolarSystemObjects().

00085 {
00086     errorMessagePrelude(tok);
00087     cerr << msg << '\n';
00088 }


Generated on Sat Jan 14 22:31:15 2006 for Celestia by  doxygen 1.4.1