00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <cassert>
00013
00014 #include <cstdio>
00015
00016 #ifndef _WIN32
00017 #ifndef MACOSX_PB
00018 #include <config.h>
00019 #endif
00020 #endif
00021
00022 #include <celutil/debug.h>
00023 #include <celmath/mathlib.h>
00024 #include <celutil/util.h>
00025 #include <cstdio>
00026 #include "astro.h"
00027 #include "parser.h"
00028 #include "texmanager.h"
00029 #include "meshmanager.h"
00030 #include "universe.h"
00031 #include "multitexture.h"
00032 #include "parseobject.h"
00033
00034 using namespace std;
00035
00036
00037 enum Disposition
00038 {
00039 AddObject,
00040 ReplaceObject,
00041 ModifyObject,
00042 };
00043
00044
00078 static void errorMessagePrelude(const Tokenizer& tok)
00079 {
00080 cerr << _("Error in .ssc file (line ") << tok.getLineNumber() << "): ";
00081 }
00082
00083 static void sscError(const Tokenizer& tok,
00084 const string& msg)
00085 {
00086 errorMessagePrelude(tok);
00087 cerr << msg << '\n';
00088 }
00089
00090
00091 static Location* CreateLocation(Hash* locationData,
00092 Body* body)
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 }
00118
00119
00120 static void FillinSurface(Hash* surfaceData,
00121 Surface* surface,
00122 const std::string& path)
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
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 }
00204
00205
00206
00207
00208
00209 static Body* CreatePlanet(PlanetarySystem* system,
00210 Body* existingBody,
00211 Hash* planetData,
00212 const string& path,
00213 Disposition disposition,
00214 bool usePlanetUnits = true)
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
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
00286
00287
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
00342
00343 }
00344
00345 ResourceHandle modelHandle = GetModelManager()->getHandle(ModelInfo(model, path, modelCenter));
00346 body->setModel(modelHandle);
00347
00348 }
00349 }
00350
00351
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
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
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 }
00447
00448
00449 bool LoadSolarSystemObjects(istream& in,
00450 Universe& universe,
00451 const std::string& directory)
00452 {
00453 Tokenizer tokenizer(&in);
00454 Parser parser(&tokenizer);
00455
00456 while (tokenizer.nextToken() != Tokenizer::TokenEnd)
00457 {
00458
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
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
00527
00528 solarSystem = universe.createSolarSystem(parent.star());
00529 }
00530 parentSystem = solarSystem->getPlanets();
00531 }
00532 else if (parent.body() != NULL)
00533 {
00534
00535 parentSystem = parent.body()->getSatellites();
00536 if (parentSystem == NULL)
00537 {
00538
00539
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
00612 return true;
00613 }
00614
00615
00616 SolarSystem::SolarSystem(Star* _star) : star(_star)
00617 {
00618 planets = new PlanetarySystem(_star);
00619 }
00620
00621
00622 Star* SolarSystem::getStar() const
00623 {
00624 return star;
00625 }
00626
00627 Point3f SolarSystem::getCenter() const
00628 {
00629
00630
00631
00632 return star->getPosition();
00633 }
00634
00635 PlanetarySystem* SolarSystem::getPlanets() const
00636 {
00637 return planets;
00638 }