00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <cassert>
00011
00012 #include <libxml/parser.h>
00013 #include <libxml/parserInternals.h>
00014 #include <libxml/SAX.h>
00015
00016 #include <celutil/debug.h>
00017 #include <celmath/mathlib.h>
00018 #include "astro.h"
00019 #include "customorbit.h"
00020 #include "texmanager.h"
00021 #include "meshmanager.h"
00022 #include "solarsysxml.h"
00023
00024 using namespace std;
00025
00026
00027 struct UnitDefinition
00028 {
00029 char* name;
00030 double conversion;
00031 };
00032
00033 UnitDefinition distanceUnits[] =
00034 {
00035 { "km", 1.0 },
00036 { "m", 0.001 },
00037 { "au", 149597870.7 },
00038 { "ly", 9466411842000.0 },
00039 };
00040
00041 UnitDefinition timeUnits[] =
00042 {
00043 { "s", 1.0 },
00044 { "m", 60.0 },
00045 { "h", 3600.0 },
00046 { "d", 86400.0 },
00047 { "y", 86400.0 * 365.25 },
00048 };
00049
00050
00051 static xmlSAXHandler emptySAXHandler =
00052 {
00053 NULL,
00054 NULL,
00055 NULL,
00056 NULL,
00057 NULL,
00058 NULL,
00059 NULL,
00060 NULL,
00061 NULL,
00062 NULL,
00063 NULL,
00064 NULL,
00065 NULL,
00066 NULL,
00067 NULL,
00068 NULL,
00069 NULL,
00070 NULL,
00071 NULL,
00072 NULL,
00073 NULL,
00074 NULL,
00075 NULL,
00076 NULL,
00077 NULL,
00078 NULL,
00079 NULL,
00080 1
00081 };
00082
00083 static xmlSAXHandler saxHandler;
00084
00085 enum ParserState {
00086 StartState,
00087 EndState,
00088 BodyState,
00089 SurfaceState,
00090 AtmosphereState,
00091 RingsState,
00092 BodyLeafState,
00093 SurfaceLeafState,
00094 AtmosphereLeafState,
00095 RingsLeafState,
00096 ErrorState,
00097 };
00098
00099 struct ParserContext
00100 {
00101 ParserState state;
00102 Body* body;
00103 Universe* universe;
00104 };
00105
00106
00107 static bool matchName(const xmlChar* s, const char* name)
00108 {
00109 while ((char) *s == *name)
00110 {
00111 if (*s == '\0')
00112 return true;
00113 s++;
00114 name++;
00115 }
00116
00117 return false;
00118 }
00119
00120
00121 static bool parseBoolean(const xmlChar* s, bool& b)
00122 {
00123 if (matchName(s, "true") || matchName(s, "1") || matchName(s, "on"))
00124 {
00125 b = true;
00126 return true;
00127 }
00128 else if (matchName(s, "false") || matchName(s, "0") || matchName(s, "off"))
00129 {
00130 b = false;
00131 return true;
00132 }
00133 else
00134 {
00135 return false;
00136 }
00137 }
00138
00139
00140 static bool parseNumber(const xmlChar* s, double& d)
00141 {
00142 return sscanf((char*) s, "%lf", &d) == 1;
00143 }
00144
00145
00146 static bool parseNumber(const xmlChar* s, float& f)
00147 {
00148 double d;
00149 if (parseNumber(s, d))
00150 {
00151 f = (float) d;
00152 return true;
00153 }
00154 else
00155 {
00156 return false;
00157 }
00158 }
00159
00160
00161 static bool parseNumberUnits(const xmlChar* s,
00162 double& d,
00163 UnitDefinition* unitTable,
00164 int unitTableLength,
00165 char* defaultUnitName)
00166 {
00167 char unitName[4];
00168 double value;
00169 int nMatched = sscanf(reinterpret_cast<const char*>(s),
00170 "%lf%3s", &value, unitName);
00171 cout << "parseNumberUnits(" << reinterpret_cast<const char*>(s) << ")\n";
00172 if (nMatched == 1)
00173 {
00174 cout << "matched = 1: " << reinterpret_cast<const char*>(s) << '\n';
00175 d = value;
00176 return true;
00177 }
00178 else if (nMatched == 2)
00179 {
00180 cout << "matched = 2: " << reinterpret_cast<const char*>(s) << '\n';
00181
00182
00183 UnitDefinition* defaultUnit = NULL;
00184 UnitDefinition* unit = NULL;
00185 int i;
00186
00187
00188 for (i = 0; i < unitTableLength; i++)
00189 {
00190 if (strcmp(defaultUnitName, unitTable[i].name) == 0)
00191 {
00192 defaultUnit = &unitTable[i];
00193 break;
00194 }
00195 }
00196 assert(defaultUnit != NULL);
00197
00198
00199 for (i = 0; i < unitTableLength; i++)
00200 {
00201 if (strcmp(unitName, unitTable[i].name) == 0)
00202 {
00203 unit = &unitTable[i];
00204 break;
00205 }
00206 }
00207
00208 if (unit != NULL)
00209 {
00210
00211 d = value * unit->conversion / defaultUnit->conversion;
00212 cout << "converting: " << value << unit->name << " = " << d << defaultUnit->name << "\n";
00213 return true;
00214 }
00215 else
00216 {
00217 return false;
00218 }
00219 }
00220 else
00221 {
00222
00223 return false;
00224 }
00225 }
00226
00227
00228 static bool parseDistance(const xmlChar* s, double& d, char* defaultUnitName)
00229 {
00230 return parseNumberUnits(s, d,
00231 distanceUnits,
00232 sizeof distanceUnits / sizeof distanceUnits[0],
00233 defaultUnitName);
00234 }
00235
00236
00237 static bool parseDistance(const xmlChar* s, float& f, char* defaultUnitName)
00238 {
00239 double d;
00240 if (parseDistance(s, d, defaultUnitName))
00241 {
00242 f = (float) d;
00243 return true;
00244 }
00245 else
00246 {
00247 return false;
00248 }
00249 }
00250
00251
00252 static bool parseAngle(const xmlChar* s, double& d)
00253 {
00254 return parseNumber(s, d);
00255 }
00256
00257
00258 static bool parseAngle(const xmlChar* s, float& f)
00259 {
00260 double d;
00261 if (parseAngle(s, d))
00262 {
00263 f = (float) d;
00264 return true;
00265 }
00266 else
00267 {
00268 return false;
00269 }
00270 }
00271
00272
00273 static bool parseTime(const xmlChar* s, double& d, char* defaultUnitName)
00274 {
00275 return parseNumberUnits(s, d,
00276 timeUnits,
00277 sizeof timeUnits / sizeof timeUnits[0],
00278 defaultUnitName);
00279 }
00280
00281
00282 static bool parseTime(const xmlChar* s, float& f, char* defaultUnitName)
00283 {
00284 double d;
00285 if (parseTime(s, d, defaultUnitName))
00286 {
00287 f = (float) d;
00288 return true;
00289 }
00290 else
00291 {
00292 return false;
00293 }
00294 }
00295
00296
00297 static bool parseEpoch(const xmlChar* s, double& d)
00298 {
00299 if (matchName(s, "J2000"))
00300 {
00301 d = astro::J2000;
00302 return true;
00303 }
00304 else
00305 {
00306 return parseNumber(s, d);
00307 }
00308 }
00309
00310
00311 static int hexDigit(char c)
00312 {
00313
00314 if (c >= '0' && c <= '9')
00315 return c - '0';
00316 else if (c >= 'a' && c <= 'f')
00317 return 10 + (c - 'a');
00318 else if (c >= 'A' && c <= 'F')
00319 return 10 + (c - 'A');
00320 else
00321 return 0;
00322 }
00323
00324
00325 ostream& operator<<(ostream& out, const Color& c)
00326 {
00327 cout << '[' << c.red() << ',' << c.green() << ',' << c.blue() << ']';
00328 return cout;
00329 }
00330
00331
00332 static bool parseColor(const xmlChar* s, Color& c)
00333 {
00334 const char* colorName = reinterpret_cast<const char*>(s);
00335 char hexColor[7];
00336 float r = 0.0f;
00337 float g = 0.0f;
00338 float b = 0.0f;
00339
00340 cout << "parsing color: " << colorName << '\n';
00341
00342 if (sscanf(colorName, " #%6[0-9a-fA-F] ", hexColor))
00343 {
00344 if (strlen(hexColor) == 6)
00345 {
00346 c = Color((hexDigit(hexColor[0]) * 16 +
00347 hexDigit(hexColor[1])) / 255.0f,
00348 (hexDigit(hexColor[2]) * 16 +
00349 hexDigit(hexColor[3])) / 255.0f,
00350 (hexDigit(hexColor[4]) * 16 +
00351 hexDigit(hexColor[5])) / 255.0f);
00352 cout << "1: " << c << '\n';
00353 return true;
00354 }
00355 else if (strlen(hexColor) == 3)
00356 {
00357 c = Color((hexDigit(hexColor[0]) * 17) / 255.0f,
00358 (hexDigit(hexColor[1]) * 17) / 255.0f,
00359 (hexDigit(hexColor[2]) * 17) / 255.0f);
00360 cout << "2: " << c << '\n';
00361 return true;
00362 }
00363 else
00364 {
00365 return false;
00366 }
00367 }
00368 else if (sscanf(colorName, " rgb( %f , %f , %f ) ", &r, &g, &b) == 3)
00369 {
00370 c = Color(r / 255.0f, g / 255.0f, b / 255.0f);
00371 cout << "3: " << c << '\n';
00372 return true;
00373 }
00374 else if (sscanf(colorName, " rgb( %f%% , %f%% , %f%% ) ", &r, &g, &b) == 3)
00375 {
00376 c = Color(r / 100.0f, g / 100.0f, b / 100.0f);
00377 cout << "4: " << c << '\n';
00378 return true;
00379 }
00380 else
00381 {
00382 return false;
00383 }
00384 }
00385
00386
00387 static bool createBody(ParserContext* ctx, const xmlChar** att)
00388 {
00389 const xmlChar* name = NULL;
00390 const xmlChar* parentName = NULL;
00391
00392
00393 if (att != NULL)
00394 {
00395 for (int i = 0; att[i] != NULL; i += 2)
00396 {
00397 if (matchName(att[i], "name"))
00398 name = att[i + 1];
00399 else if (matchName(att[i], "parent"))
00400 parentName = att[i + 1];
00401 }
00402 }
00403
00404
00405 if (name == NULL)
00406 {
00407 return false;
00408 }
00409 else if (parentName == NULL)
00410 {
00411 return false;
00412 }
00413
00414 bool orbitsPlanet = false;
00415 Selection parent = ctx->universe->findPath(reinterpret_cast<const char*>(parentName), NULL, 0);
00416 PlanetarySystem* parentSystem = NULL;
00417 if (parent.star != NULL)
00418 {
00419 SolarSystem* solarSystem = ctx->universe->getSolarSystem(parent.star);
00420 if (solarSystem == NULL)
00421 {
00422
00423
00424 solarSystem = ctx->universe->createSolarSystem(parent.star);
00425 }
00426 parentSystem = solarSystem->getPlanets();
00427 }
00428 else if (parent.body != NULL)
00429 {
00430
00431 parentSystem = parent.body->getSatellites();
00432 if (parentSystem == NULL)
00433 {
00434
00435
00436 parentSystem = new PlanetarySystem(parent.body);
00437 parent.body->setSatellites(parentSystem);
00438 }
00439 orbitsPlanet = true;
00440 }
00441 else
00442 {
00443 cout << "Parent body '" << parentName << "' of '" << name << "' not found.\n";
00444 return false;
00445 }
00446
00447 if (parentSystem != NULL)
00448 {
00449 ctx->body = new Body(parentSystem);
00450 ctx->body->setName(reinterpret_cast<const char*>(name));
00451 parentSystem->addBody(ctx->body);
00452 return true;
00453 }
00454
00455 return false;
00456 }
00457
00458
00459 static ResourceHandle createTexture(ParserContext* ctx, const xmlChar** att)
00460 {
00461 const xmlChar* type = reinterpret_cast<const xmlChar*>("base");
00462 const xmlChar* image = NULL;
00463 bool compress = false;
00464
00465
00466 if (att != NULL)
00467 {
00468 for (int i = 0; att[i] != NULL; i += 2)
00469 {
00470 if (matchName(att[i], "type"))
00471 type = att[i + 1];
00472 else if (matchName(att[i], "image"))
00473 image = att[i + 1];
00474 else if (matchName(att[i], "compress"))
00475 parseBoolean(att[i + 1], compress);
00476 }
00477 }
00478
00479 if (image == NULL)
00480 {
00481 cout << "Texture has no image source.\n";
00482 return false;
00483 }
00484
00485 ResourceHandle texHandle = GetTextureManager()->getHandle(TextureInfo(reinterpret_cast<const char*>(image), compress));
00486 if (ctx->state == SurfaceState)
00487 {
00488 assert(ctx->body != NULL);
00489
00490 if (matchName(type, "base"))
00491 ctx->body->getSurface().baseTexture = texHandle;
00492 else if (matchName(type, "night"))
00493 ctx->body->getSurface().nightTexture = texHandle;
00494 }
00495 else if (ctx->state == AtmosphereState)
00496 {
00497 assert(ctx->body != NULL);
00498 Atmosphere* atmosphere = ctx->body->getAtmosphere();
00499 assert(atmosphere != NULL);
00500
00501 if (matchName(type, "base"))
00502 atmosphere->cloudTexture = texHandle;
00503 }
00504 else if (ctx->state == RingsState)
00505 {
00506 assert(ctx->body != NULL);
00507 assert(ctx->body->getRings() != NULL);
00508
00509 if (matchName(type, "base"))
00510 ctx->body->getRings()->texture = texHandle;
00511 }
00512
00513 return true;
00514 }
00515
00516
00517 static ResourceHandle createBumpMap(ParserContext* ctx, const xmlChar** att)
00518 {
00519 const xmlChar* heightmap = NULL;
00520 float bumpHeight = 2.5f;
00521
00522
00523 if (att != NULL)
00524 {
00525 for (int i = 0; att[i] != NULL; i += 2)
00526 {
00527 if (matchName(att[i], "heightmap"))
00528 heightmap = att[i + 1];
00529 else if (matchName(att[i], "bump-height"))
00530 parseNumber(att[i + 1], bumpHeight);
00531 }
00532 }
00533
00534 if (heightmap == NULL)
00535 {
00536 cout << "Bump map has no height map source.\n";
00537 return false;
00538 }
00539
00540 ResourceHandle texHandle = GetTextureManager()->getHandle(TextureInfo(reinterpret_cast<const char*>(heightmap), bumpHeight));
00541 if (ctx->state == SurfaceState)
00542 {
00543 assert(ctx->body != NULL);
00544 if (texHandle != InvalidResource)
00545 {
00546 ctx->body->getSurface().bumpTexture = texHandle;
00547 ctx->body->getSurface().appearanceFlags |= Surface::ApplyBumpMap;
00548 }
00549 return true;
00550 }
00551 else
00552 {
00553 return false;
00554 }
00555 }
00556
00557
00558 static bool createAtmosphere(ParserContext* ctx, const xmlChar** att)
00559 {
00560 Atmosphere* atmosphere = new Atmosphere();
00561
00562 if (att != NULL)
00563 {
00564 for (int i = 0; att[i] != NULL; i += 2)
00565 {
00566 if (matchName(att[i], "height"))
00567 parseDistance(att[i + 1], atmosphere->height, "km");
00568 else if (matchName(att[i], "lower-color"))
00569 parseColor(att[i + 1], atmosphere->lowerColor);
00570 else if (matchName(att[i], "upper-color"))
00571 parseColor(att[i + 1], atmosphere->upperColor);
00572 else if (matchName(att[i], "sky-color"))
00573 parseColor(att[i + 1], atmosphere->skyColor);
00574 else if (matchName(att[i], "cloud-height"))
00575 parseDistance(att[i + 1], atmosphere->cloudHeight, "km");
00576 else if (matchName(att[i], "cloud-speed"))
00577 parseAngle(att[i + 1], atmosphere->cloudSpeed);
00578 }
00579 }
00580
00581 assert(ctx->body != NULL);
00582 ctx->body->setAtmosphere(*atmosphere);
00583 delete atmosphere;
00584
00585 return true;
00586 }
00587
00588
00589 static bool createHaze(ParserContext* ctx, const xmlChar** att)
00590 {
00591 Color hazeColor;
00592 float hazeDensity = 0.0f;
00593
00594 if (att != NULL)
00595 {
00596 for (int i = 0; att[i] != NULL; i += 2)
00597 {
00598 if (matchName(att[i], "density"))
00599 parseNumber(att[i + 1], hazeDensity);
00600 else if (matchName(att[i], "color"))
00601 parseColor(att[i + 1], hazeColor);
00602 }
00603 }
00604
00605 assert(ctx->body != NULL);
00606 ctx->body->getSurface().hazeColor = Color(hazeColor.red(),
00607 hazeColor.green(),
00608 hazeColor.blue(),
00609 hazeDensity);
00610
00611 return true;
00612 }
00613
00614
00615 static bool createSurface(ParserContext* ctx, const xmlChar** att)
00616 {
00617 Color color(1.0f, 1.0f, 1.0f);
00618 Color specularColor(0.0f, 0.0f, 0.0f);
00619 float specularPower = 0.0f;
00620 float albedo = 0.5f;
00621 bool blendTexture = false;
00622 bool emissive = false;
00623
00624 if (att != NULL)
00625 {
00626 for (int i = 0; att[i] != NULL; i += 2)
00627 {
00628 if (matchName(att[i], "color"))
00629 parseColor(att[i + 1], color);
00630 if (matchName(att[i], "specular-color"))
00631 parseColor(att[i + 1], specularColor);
00632 if (matchName(att[i], "specular-power"))
00633 parseNumber(att[i + 1], specularPower);
00634 if (matchName(att[i], "blend-texture"))
00635 parseBoolean(att[i + 1], blendTexture);
00636 if (matchName(att[i], "emissive"))
00637 parseBoolean(att[i + 1], emissive);
00638 if (matchName(att[i], "albedo"))
00639 parseNumber(att[i + 1], albedo);
00640 }
00641 }
00642
00643 assert(ctx->body != NULL);
00644 ctx->body->setAlbedo(albedo);
00645 ctx->body->getSurface().color = color;
00646 ctx->body->getSurface().specularColor = specularColor;
00647 ctx->body->getSurface().specularPower = specularPower;
00648 if (blendTexture)
00649 ctx->body->getSurface().appearanceFlags |= Surface::BlendTexture;
00650 if (emissive)
00651 ctx->body->getSurface().appearanceFlags |= Surface::Emissive;
00652
00653 return true;
00654 }
00655
00656
00657 static bool createEllipticalOrbit(ParserContext* ctx, const xmlChar** att)
00658 {
00659
00660
00661 double pericenterDistance = 0.0;
00662 double semiMajorAxis = 0.0;
00663 double period = 0.0;
00664 double eccentricity = 0.0;
00665 double inclination = 0.0;
00666 double ascendingNode = 0.0;
00667 double argOfPericenter = 0.0;
00668 double anomalyAtEpoch = 0.0;
00669 double epoch = astro::J2000;
00670 bool foundPeriod = false;
00671 bool foundSMA = false;
00672 bool foundPD = false;
00673
00674
00675
00676
00677 if (att != NULL)
00678 {
00679 int i;
00680 for (i = 0; att[i] != NULL; i += 2)
00681 {
00682 if (matchName(att[i], "period"))
00683 {
00684 foundPeriod = true;
00685 parseTime(att[i + 1], period, "d");
00686 }
00687 else if (matchName(att[i], "semi-major-axis"))
00688 {
00689 foundSMA = true;
00690 parseDistance(att[i + 1], semiMajorAxis, "km");
00691 cout << "SMA: " << semiMajorAxis << '\n';
00692 }
00693 else if (matchName(att[i], "pericenter-distance"))
00694 {
00695 foundPD = true;
00696 parseDistance(att[i + 1], pericenterDistance, "km");
00697 }
00698 else if (matchName(att[i], "epoch"))
00699 parseEpoch(att[i + 1], epoch);
00700 else if (matchName(att[i], "eccentricity"))
00701 parseNumber(att[i + 1], eccentricity);
00702 else if (matchName(att[i], "inclination"))
00703 parseAngle(att[i + 1], inclination);
00704 else if (matchName(att[i], "ascending-node"))
00705 parseAngle(att[i + 1], ascendingNode);
00706 }
00707
00708
00709
00710
00711
00712 for (i = 0; att[i] != NULL; i += 2)
00713 {
00714 if (matchName(att[i], "arg-of-pericenter"))
00715 {
00716 parseAngle(att[i + 1], argOfPericenter);
00717 }
00718 else if (matchName(att[i + 1], "long-of-pericenter"))
00719 {
00720 double longOfPericenter;
00721 parseAngle(att[i + 1], longOfPericenter);
00722 argOfPericenter = longOfPericenter - ascendingNode;
00723 }
00724 }
00725
00726
00727
00728
00729 for (i = 0; att[i] != NULL; i += 2)
00730 {
00731 if (matchName(att[i], "mean-anomaly"))
00732 {
00733 parseAngle(att[i + 1], anomalyAtEpoch);
00734 }
00735 else if (matchName(att[i + 1], "mean-longitude"))
00736 {
00737 double longAtEpoch;
00738 parseAngle(att[i + 1], longAtEpoch);
00739 anomalyAtEpoch = longAtEpoch - (argOfPericenter + ascendingNode);
00740 }
00741 }
00742 }
00743
00744 if (!foundPeriod)
00745 {
00746 return false;
00747 }
00748 else if (!foundSMA && !foundPD)
00749 {
00750 return false;
00751 }
00752
00753
00754
00755 if (foundSMA)
00756 pericenterDistance = semiMajorAxis * (1.0 - eccentricity);
00757
00758 EllipticalOrbit* orbit = new EllipticalOrbit(pericenterDistance,
00759 eccentricity,
00760 degToRad(inclination),
00761 degToRad(ascendingNode),
00762 degToRad(argOfPericenter),
00763 degToRad(anomalyAtEpoch),
00764 period,
00765 epoch);
00766 assert(ctx->body != NULL);
00767
00768
00769
00770 if (ctx->body->getOrbit() == NULL)
00771 ctx->body->setOrbit(orbit);
00772 else
00773 delete orbit;
00774
00775 return true;
00776 }
00777
00778
00779 static bool createCustomOrbit(ParserContext* ctx, const xmlChar** att)
00780 {
00781 const xmlChar* name = NULL;
00782
00783
00784 if (att != NULL)
00785 {
00786 for (int i = 0; att[i] != NULL; i += 2)
00787 {
00788 if (matchName(att[i], "name"))
00789 name = att[i + 1];
00790 }
00791 }
00792
00793 if (name == NULL)
00794 return false;
00795
00796 Orbit* orbit = GetCustomOrbit(reinterpret_cast<const char*>(name));
00797 if (orbit == NULL)
00798 {
00799 DPRINTF(0, "Could not find custom orbit named '%s'\n",
00800 reinterpret_cast<const char*>(name));
00801 }
00802 else
00803 {
00804 assert(ctx->body != NULL);
00805 ctx->body->setOrbit(orbit);
00806 }
00807
00808 return true;
00809 }
00810
00811
00812 static bool createRotation(ParserContext* ctx, const xmlChar** att)
00813 {
00814 double period = 0.0;
00815 double obliquity = 0.0;
00816 double axisLongitude = 0.0;
00817 double offset = 0.0;
00818 double epoch = astro::J2000;
00819
00820 if (att != NULL)
00821 {
00822 for (int i = 0; att[i] != NULL; i += 2)
00823 {
00824 if (matchName(att[i], "period"))
00825 {
00826 if (matchName(att[i + 1], "sync"))
00827 period = 0.0;
00828 else
00829 parseTime(att[i + 1], period, "h");
00830 }
00831 else if (matchName(att[i], "obliquity"))
00832 parseAngle(att[i + 1], obliquity);
00833 else if (matchName(att[i], "axis-longitude"))
00834 parseAngle(att[i + 1], axisLongitude);
00835 else if (matchName(att[i], "offset"))
00836 parseAngle(att[i + 1], offset);
00837 else if (matchName(att[i], "epoch"))
00838 parseEpoch(att[i + 1], epoch);
00839 }
00840 }
00841
00842 assert(ctx->body != NULL);
00843
00844 RotationElements re;
00845
00846
00847
00848
00849 Orbit* orbit = ctx->body->getOrbit();
00850 if (orbit == NULL)
00851 return false;
00852
00853 if (period == 0.0)
00854 re.period = (float) orbit->getPeriod();
00855 else
00856 re.period = (float) period / 24.0f;
00857 re.obliquity = (float) degToRad(obliquity);
00858 re.axisLongitude = (float) degToRad(axisLongitude);
00859 re.offset = (float) degToRad(offset);
00860 re.epoch = epoch;
00861 ctx->body->setRotationElements(re);
00862
00863 return true;
00864 }
00865
00866
00867 static bool createGeometry(ParserContext* ctx, const xmlChar** att)
00868 {
00869 double radius = 1.0;
00870 double oblateness = 0.0;
00871 const xmlChar* meshName = NULL;
00872
00873
00874 if (att != NULL)
00875 {
00876 for (int i = 0; att[i] != NULL; i += 2)
00877 {
00878 if (matchName(att[i], "radius"))
00879 parseDistance(att[i + 1], radius, "km");
00880 else if (matchName(att[i], "mesh"))
00881 meshName = att[i + 1];
00882 else if (matchName(att[i], "oblateness"))
00883 parseNumber(att[i + 1], oblateness);
00884 }
00885 }
00886
00887 assert(ctx->body != NULL);
00888
00889 ResourceHandle meshHandle = InvalidResource;
00890 if (meshName != NULL)
00891 meshHandle = GetMeshManager()->getHandle(MeshInfo(reinterpret_cast<const char*>(meshName)));
00892 ctx->body->setMesh(meshHandle);
00893 ctx->body->setRadius((float) radius);
00894 ctx->body->setOblateness((float) oblateness);
00895
00896 return false;
00897 }
00898
00899
00900 static bool createRings(ParserContext* ctx, const xmlChar** att)
00901 {
00902 double innerRadius = 0.0;
00903 double outerRadius = 0.0;
00904 Color color(1.0f, 1.0f, 1.0f);
00905
00906
00907 if (att != NULL)
00908 {
00909 for (int i = 0; att[i] != NULL; i += 2)
00910 {
00911 if (matchName(att[i], "inner-radius"))
00912 parseDistance(att[i + 1], innerRadius, "km");
00913 else if (matchName(att[i], "outer-radius"))
00914 parseDistance(att[i + 1], outerRadius, "km");
00915 else if (matchName(att[i], "color"))
00916 parseColor(att[i + 1], color);
00917 }
00918 }
00919
00920 assert(ctx->body != NULL);
00921 ctx->body->setRings(RingSystem(innerRadius, outerRadius, color));
00922
00923 return true;
00924 }
00925
00926
00927
00928 static void solarSysStartDocument(void* data)
00929 {
00930 ParserContext* ctx = reinterpret_cast<ParserContext*>(data);
00931 ctx->state = StartState;
00932 ctx->body = NULL;
00933 }
00934
00935
00936
00937 static void solarSysEndDocument(void* data)
00938 {
00939 ParserContext* ctx = reinterpret_cast<ParserContext*>(data);
00940 ctx->state = EndState;
00941 ctx->body = NULL;
00942 }
00943
00944
00945
00946 static void solarSysStartElement(void* data,
00947 const xmlChar* name,
00948 const xmlChar** att)
00949 {
00950 ParserContext* ctx = reinterpret_cast<ParserContext*>(data);
00951
00952 switch (ctx->state)
00953 {
00954 case ErrorState:
00955 return;
00956
00957 case StartState:
00958 if (matchName(name, "body"))
00959 {
00960 createBody(ctx, att);
00961 ctx->state = BodyState;
00962 }
00963 else if (!matchName(name, "catalog"))
00964 {
00965 ctx->state = ErrorState;
00966 }
00967 break;
00968
00969 case BodyState:
00970 if (matchName(name, "surface"))
00971 {
00972 createSurface(ctx, att);
00973 ctx->state = SurfaceState;
00974 }
00975 else if (matchName(name, "geometry"))
00976 {
00977 createGeometry(ctx, att);
00978 ctx->state = BodyLeafState;
00979 }
00980 else if (matchName(name, "elliptical"))
00981 {
00982 createEllipticalOrbit(ctx, att);
00983 ctx->state = BodyLeafState;
00984 }
00985 else if (matchName(name, "customorbit"))
00986 {
00987 createCustomOrbit(ctx, att);
00988 ctx->state = BodyLeafState;
00989 }
00990 else if (matchName(name, "rotation"))
00991 {
00992 createRotation(ctx, att);
00993 ctx->state = BodyLeafState;
00994 }
00995 else if (matchName(name, "atmosphere"))
00996 {
00997 createAtmosphere(ctx, att);
00998 ctx->state = AtmosphereState;
00999 }
01000 else if (matchName(name, "rings"))
01001 {
01002 createRings(ctx, att);
01003 ctx->state = RingsState;
01004 }
01005 else
01006 {
01007 ctx->state = ErrorState;
01008 }
01009 break;
01010
01011 case SurfaceState:
01012 if (matchName(name, "texture"))
01013 {
01014 createTexture(ctx, att);
01015 ctx->state = SurfaceLeafState;
01016 }
01017 else if (matchName(name, "bumpmap"))
01018 {
01019 createBumpMap(ctx, att);
01020 ctx->state = SurfaceLeafState;
01021 }
01022 else if (matchName(name, "haze"))
01023 {
01024 createHaze(ctx, att);
01025 ctx->state = SurfaceLeafState;
01026 }
01027 else
01028 {
01029 ctx->state = ErrorState;
01030 }
01031 break;
01032
01033 case RingsState:
01034 if (matchName(name, "texture"))
01035 {
01036 createTexture(ctx, att);
01037 ctx->state = RingsLeafState;
01038 }
01039 break;
01040
01041 case AtmosphereState:
01042 if (matchName(name, "texture"))
01043 {
01044 createTexture(ctx, att);
01045 ctx->state = AtmosphereLeafState;
01046 }
01047 break;
01048
01049 case BodyLeafState:
01050 case SurfaceLeafState:
01051 case AtmosphereLeafState:
01052 case RingsLeafState:
01053 ctx->state = ErrorState;
01054 break;
01055
01056 default:
01057 break;
01058 }
01059
01060 if (ctx->state == ErrorState)
01061 {
01062 cout << "Error! " << name << " element not expected.\n";
01063 }
01064 }
01065
01066
01067
01068 static void solarSysEndElement(void* data, const xmlChar* name)
01069 {
01070 ParserContext* ctx = reinterpret_cast<ParserContext*>(data);
01071 switch (ctx->state)
01072 {
01073 case ErrorState:
01074 return;
01075
01076 case BodyState:
01077 if (matchName(name, "body"))
01078 {
01079 assert(ctx->body != NULL);
01080 if (ctx->body->getOrbit() == NULL)
01081 {
01082 DPRINTF(0, "Object %s has no orbit! Removing . . .\n",
01083 ctx->body->getName().c_str());
01084
01085 }
01086 ctx->body = NULL;
01087 ctx->state = StartState;
01088 }
01089 else
01090 {
01091 ctx->state = ErrorState;
01092 }
01093 break;
01094
01095 case SurfaceState:
01096 if (matchName(name, "surface"))
01097 ctx->state = BodyState;
01098 else
01099 ctx->state = ErrorState;
01100 break;
01101
01102 case AtmosphereState:
01103 if (matchName(name, "atmosphere"))
01104 ctx->state = BodyState;
01105 else
01106 ctx->state = ErrorState;
01107 break;
01108
01109 case RingsState:
01110 if (matchName(name, "rings"))
01111 ctx->state = BodyState;
01112 else
01113 ctx->state = ErrorState;
01114 break;
01115
01116 case BodyLeafState:
01117 if (matchName(name, "geometry") ||
01118 matchName(name, "elliptical") ||
01119 matchName(name, "customorbit") ||
01120 matchName(name, "rotation"))
01121 {
01122 ctx->state = BodyState;
01123 }
01124 break;
01125
01126 case SurfaceLeafState:
01127 if (matchName(name, "texture") ||
01128 matchName(name, "haze") ||
01129 matchName(name, "bumpmap"))
01130 {
01131 ctx->state = SurfaceState;
01132 }
01133 break;
01134
01135 case AtmosphereLeafState:
01136 if (matchName(name, "texture"))
01137 ctx->state = AtmosphereState;
01138 break;
01139
01140 case RingsLeafState:
01141 if (matchName(name, "texture"))
01142 ctx->state = RingsState;
01143 break;
01144
01145 default:
01146 break;
01147 }
01148
01149 if (ctx->state == ErrorState)
01150 {
01151 cout << "Error! End of " << name << " element not expected.\n";
01152 }
01153 }
01154
01155
01156 static void initSAXHandler(xmlSAXHandler& sax)
01157 {
01158 sax = emptySAXHandler;
01159 sax.startDocument = solarSysStartDocument;
01160 sax.endDocument = solarSysEndDocument;
01161 sax.startElement = solarSysStartElement;
01162 sax.endElement = solarSysEndElement;
01163 }
01164
01165
01166 static bool parseSolarSystemXML(xmlSAXHandlerPtr sax,
01167 void* userData,
01168 const char* filename)
01169 {
01170 xmlParserCtxtPtr ctxt = xmlCreateFileParserCtxt(filename);
01171 if (ctxt == NULL)
01172 return false;
01173
01174 ctxt->sax = sax;
01175 ctxt->userData = userData;
01176
01177 xmlParseDocument(ctxt);
01178
01179 int wellFormed = ctxt->wellFormed;
01180 if (sax != NULL)
01181 ctxt->sax = NULL;
01182 xmlFreeParserCtxt(ctxt);
01183
01184 cout << "Well formed: " << wellFormed << '\n';
01185
01186 return wellFormed != 0;
01187 }
01188
01189
01190 bool LoadSolarSystemObjectsXML(const string& source, Universe& universe)
01191 {
01192 initSAXHandler(saxHandler);
01193
01194 ParserContext ctx;
01195 ctx.universe = &universe;
01196
01197 if (!parseSolarSystemXML(&saxHandler, &ctx, source.c_str()))
01198 {
01199 cout << "Error parsing " << source << '\n';
01200 return false;
01201 }
01202
01203 return true;
01204 }