celx_object.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:45k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // celx_object.cpp
  2. //
  3. // Copyright (C) 2003-2009, the Celestia Development Team
  4. //
  5. // Lua script extensions for Celestia: object
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. #include <cstring>
  12. #include "celx.h"
  13. #include "celx_internal.h"
  14. #include "celx_object.h"
  15. #include <celengine/body.h>
  16. #include <celengine/timelinephase.h>
  17. #include <celengine/axisarrow.h>
  18. #include <celengine/visibleregion.h>
  19. #include <celengine/planetgrid.h>
  20. #include "celestiacore.h"
  21. using namespace std;
  22. static MarkerRepresentation::Symbol parseMarkerSymbol(const string& name)
  23. {
  24.     if (compareIgnoringCase(name, "diamond") == 0)
  25.         return MarkerRepresentation::Diamond;
  26.     else if (compareIgnoringCase(name, "triangle") == 0)
  27.         return MarkerRepresentation::Triangle;
  28.     else if (compareIgnoringCase(name, "square") == 0)
  29.         return MarkerRepresentation::Square;
  30.     else if (compareIgnoringCase(name, "filledsquare") == 0)
  31.         return MarkerRepresentation::FilledSquare;
  32.     else if (compareIgnoringCase(name, "plus") == 0)
  33.         return MarkerRepresentation::Plus;
  34.     else if (compareIgnoringCase(name, "x") == 0)
  35.         return MarkerRepresentation::X;
  36.     else if (compareIgnoringCase(name, "leftarrow") == 0)
  37.         return MarkerRepresentation::LeftArrow;
  38.     else if (compareIgnoringCase(name, "rightarrow") == 0)
  39.         return MarkerRepresentation::RightArrow;
  40.     else if (compareIgnoringCase(name, "uparrow") == 0)
  41.         return MarkerRepresentation::UpArrow;
  42.     else if (compareIgnoringCase(name, "downarrow") == 0)
  43.         return MarkerRepresentation::DownArrow;
  44.     else if (compareIgnoringCase(name, "circle") == 0)
  45.         return MarkerRepresentation::Circle;
  46.     else if (compareIgnoringCase(name, "disk") == 0)
  47.         return MarkerRepresentation::Disk;
  48.     else
  49.         return MarkerRepresentation::Diamond;
  50. }
  51. // ==================== Object ====================
  52. // star, planet, or deep-sky object
  53. int object_new(lua_State* l, const Selection& sel)
  54. {
  55.     CelxLua celx(l);
  56.     
  57.     Selection* ud = reinterpret_cast<Selection*>(lua_newuserdata(l, sizeof(Selection)));
  58.     *ud = sel;
  59.     
  60.     celx.setClass(Celx_Object);
  61.     
  62.     return 1;
  63. }
  64. Selection* to_object(lua_State* l, int index)
  65. {
  66.     CelxLua celx(l);
  67.     return static_cast<Selection*>(celx.checkUserData(index, Celx_Object));
  68. }
  69. static Selection* this_object(lua_State* l)
  70. {
  71.     CelxLua celx(l);
  72.     Selection* sel = to_object(l, 1);
  73.     if (sel == NULL)
  74.     {
  75.         celx.doError("Bad position object!");
  76.     }
  77.     
  78.     return sel;
  79. }
  80. static int object_tostring(lua_State* l)
  81. {
  82.     lua_pushstring(l, "[Object]");
  83.     
  84.     return 1;
  85. }
  86. // Return true if the object is visible, false if not.
  87. static int object_visible(lua_State* l)
  88. {
  89.     CelxLua celx(l);
  90.     celx.checkArgs(1, 1, "No arguments expected to function object:visible");
  91.     
  92.     Selection* sel = this_object(l);
  93.     lua_pushboolean(l, sel->isVisible());
  94.     
  95.     return 1;
  96. }
  97. // Set the object visibility flag.
  98. static int object_setvisible(lua_State* l)
  99. {
  100.     CelxLua celx(l);
  101.     celx.checkArgs(2, 2, "One argument expected to object:setvisible()");
  102.     
  103.     Selection* sel = this_object(l);
  104.     bool visible = celx.safeGetBoolean(2, AllErrors, "Argument to object:setvisible() must be a boolean");
  105.     if (sel->body() != NULL)
  106.     {
  107.         sel->body()->setVisible(visible);
  108.     }
  109.     else if (sel->deepsky() != NULL)
  110.     {
  111.         sel->deepsky()->setVisible(visible);
  112.     }
  113.     
  114.     return 0;
  115. }
  116. static int object_setorbitcolor(lua_State* l)
  117. {
  118.     CelxLua celx(l);
  119.     celx.checkArgs(4, 4, "Red, green, and blue color values exepected for object:setorbitcolor()");
  120.     
  121.     Selection* sel = this_object(l);
  122.     float r = (float) celx.safeGetNumber(2, WrongType, "Argument 1 to object:setorbitcolor() must be a number", 0.0);
  123.     float g = (float) celx.safeGetNumber(3, WrongType, "Argument 2 to object:setorbitcolor() must be a number", 0.0);
  124.     float b = (float) celx.safeGetNumber(4, WrongType, "Argument 3 to object:setorbitcolor() must be a number", 0.0);
  125.     Color orbitColor(r, g, b);
  126.     
  127.     if (sel->body() != NULL)
  128.     {
  129.         sel->body()->setOrbitColor(orbitColor);
  130.     }
  131.     
  132.     return 0;
  133. }
  134. static int object_orbitcoloroverridden(lua_State* l)
  135. {
  136.     CelxLua celx(l);
  137.     celx.checkArgs(1, 1, "No arguments expected to object:orbitcoloroverridden");
  138.     
  139.     bool isOverridden = false;
  140.     Selection* sel = this_object(l);
  141.     if (sel->body() != NULL)
  142.     {
  143.         isOverridden = sel->body()->isOrbitColorOverridden();
  144.     }
  145.     
  146.     lua_pushboolean(l, isOverridden);
  147.     
  148.     return 1;
  149. }
  150. static int object_setorbitcoloroverridden(lua_State* l)
  151. {
  152.     CelxLua celx(l);
  153.     celx.checkArgs(2, 2, "One argument expected to object:setorbitcoloroverridden");
  154.     
  155.     Selection* sel = this_object(l);
  156.     bool override = celx.safeGetBoolean(2, AllErrors, "Argument to object:setorbitcoloroverridden() must be a boolean");
  157.     
  158.     if (sel->body() != NULL)
  159.     {
  160.         sel->body()->setOrbitColorOverridden(override);
  161.     }
  162.     
  163.     return 0;
  164. }
  165. static int object_orbitvisibility(lua_State* l)
  166. {
  167.     CelxLua celx(l);
  168.     celx.checkArgs(1, 1, "No arguments expected to object:orbitvisibility");
  169.     
  170.     Body::VisibilityPolicy visibility = Body::UseClassVisibility;
  171.     
  172.     Selection* sel = this_object(l);
  173.     if (sel->body() != NULL)
  174.     {
  175.         visibility = sel->body()->getOrbitVisibility();
  176.     }
  177.     
  178.     const char* s = "normal";
  179.     if (visibility == Body::AlwaysVisible)
  180.         s = "always";
  181.     else if (visibility == Body::NeverVisible)
  182.         s = "never";
  183.     
  184.     lua_pushstring(l, s);
  185.     
  186.     return 1;
  187. }
  188. static int object_setorbitvisibility(lua_State* l)
  189. {
  190.     CelxLua celx(l);
  191.     celx.checkArgs(2, 2, "One argument expected to object:setorbitcoloroverridden");
  192.     
  193.     if (!lua_isstring(l, 2))
  194.     {
  195.         celx.doError("First argument to object:setorbitvisibility() must be a string");
  196.     }
  197.     
  198.     Selection* sel = this_object(l);
  199.     
  200.     string key;
  201.     key = lua_tostring(l, 2);
  202.     
  203.     if (CelxLua::OrbitVisibilityMap.count(key) == 0)
  204.     {
  205.         cerr << "Unknown visibility policy: " << key << endl;
  206.     }
  207.     else
  208.     {
  209.         Body::VisibilityPolicy visibility = static_cast<Body::VisibilityPolicy>(CelxLua::OrbitVisibilityMap[key]);
  210.         
  211.         if (sel->body() != NULL)
  212.         {
  213.             sel->body()->setOrbitVisibility(visibility);
  214.         }
  215.     }
  216.     
  217.     return 0;
  218. }
  219. static int object_addreferencemark(lua_State* l)
  220. {
  221.     CelxLua celx(l);
  222.     celx.checkArgs(2, 2, "Expected one table as argument to object:addreferencemark()");
  223.     
  224.     if (!lua_istable(l, 2))
  225.     {
  226.         celx.doError("Argument to object:addreferencemark() must be a table");
  227.     }
  228.     
  229.     Selection* sel = this_object(l);
  230.     Body* body = sel->body();
  231.     
  232.     lua_pushstring(l, "type");
  233.     lua_gettable(l, 2);
  234.     const char* rmtype = celx.safeGetString(3, NoErrors, "");
  235.     lua_settop(l, 2);
  236.     
  237.     lua_pushstring(l, "size");
  238.     lua_gettable(l, 2);
  239.     float rmsize = (float) celx.safeGetNumber(3, NoErrors, "", body->getRadius()) + body->getRadius();
  240.     lua_settop(l, 2);
  241.     
  242.     lua_pushstring(l, "opacity");
  243.     lua_gettable(l, 2);
  244.     // -1 indicates that the opacity wasn't set and the default value
  245.     // should be used.
  246.     float rmopacity = (float) celx.safeGetNumber(3, NoErrors, "", -1.0f);
  247.     lua_settop(l, 2);
  248.     
  249.     lua_pushstring(l, "color");
  250.     lua_gettable(l, 2);
  251.     const char* rmcolorstring = celx.safeGetString(3, NoErrors, "");
  252.     Color rmcolor(0.0f, 1.0f, 0.0f);
  253.     if (rmcolorstring != NULL)
  254.         Color::parse(rmcolorstring, rmcolor);
  255.     lua_settop(l, 2);
  256.     
  257.     lua_pushstring(l, "tag");
  258.     lua_gettable(l, 2);
  259.     const char* rmtag = celx.safeGetString(3, NoErrors, "");
  260.     if (rmtag == NULL)
  261.         rmtag = rmtype;
  262.     lua_settop(l, 2);
  263.     
  264.     lua_pushstring(l, "target");
  265.     lua_gettable(l, 2);
  266.     Selection* rmtarget = to_object(l, 3);
  267.     lua_settop(l, 2);
  268.     
  269.     if (rmtype != NULL)
  270.     {
  271.         body->removeReferenceMark(rmtype);
  272.         
  273.         if (compareIgnoringCase(rmtype, "body axes") == 0)
  274.         {
  275.             BodyAxisArrows* arrow = new BodyAxisArrows(*body);
  276.             arrow->setTag(rmtag);
  277.             arrow->setSize(rmsize);
  278.             if (rmopacity >= 0.0f)
  279.                 arrow->setOpacity(rmopacity);
  280.             body->addReferenceMark(arrow);
  281.         }
  282.         else if (compareIgnoringCase(rmtype, "frame axes") == 0)
  283.         {
  284.             FrameAxisArrows* arrow = new FrameAxisArrows(*body);
  285.             arrow->setTag(rmtag);
  286.             arrow->setSize(rmsize);
  287.             if (rmopacity >= 0.0f)
  288.                 arrow->setOpacity(rmopacity);
  289.             body->addReferenceMark(arrow);
  290.         }
  291.         else if (compareIgnoringCase(rmtype, "sun direction") == 0)
  292.         {
  293.             SunDirectionArrow* arrow = new SunDirectionArrow(*body);
  294.             arrow->setTag(rmtag);
  295.             arrow->setSize(rmsize);
  296.             if (rmcolorstring != NULL)
  297.                 arrow->setColor(rmcolor);
  298.             body->addReferenceMark(arrow);
  299.         }
  300.         else if (compareIgnoringCase(rmtype, "velocity vector") == 0)
  301.         {
  302.             VelocityVectorArrow* arrow = new VelocityVectorArrow(*body);
  303.             arrow->setTag(rmtag);
  304.             arrow->setSize(rmsize);
  305.             if (rmcolorstring != NULL)
  306.                 arrow->setColor(rmcolor);
  307.             body->addReferenceMark(arrow);
  308.         }
  309.         else if (compareIgnoringCase(rmtype, "spin vector") == 0)
  310.         {
  311.             SpinVectorArrow* arrow = new SpinVectorArrow(*body);
  312.             arrow->setTag(rmtag);
  313.             arrow->setSize(rmsize);
  314.             if (rmcolorstring != NULL)
  315.                 arrow->setColor(rmcolor);
  316.             body->addReferenceMark(arrow);
  317.         }
  318.         else if (compareIgnoringCase(rmtype, "body to body direction") == 0 && rmtarget != NULL)
  319.         {
  320.             BodyToBodyDirectionArrow* arrow = new BodyToBodyDirectionArrow(*body, *rmtarget);
  321.             arrow->setTag(rmtag);
  322.             arrow->setSize(rmsize);
  323.             if (rmcolorstring != NULL)
  324.                 arrow->setColor(rmcolor);
  325.             body->addReferenceMark(arrow);
  326.         }
  327.         else if (compareIgnoringCase(rmtype, "visible region") == 0 && rmtarget != NULL)
  328.         {
  329.             VisibleRegion* region = new VisibleRegion(*body, *rmtarget);
  330.             region->setTag(rmtag);
  331.             if (rmopacity >= 0.0f)
  332.                 region->setOpacity(rmopacity);
  333.             if (rmcolorstring != NULL)
  334.                 region->setColor(rmcolor);
  335.             body->addReferenceMark(region);
  336.         }
  337.         else if (compareIgnoringCase(rmtype, "planetographic grid") == 0)
  338.         {
  339.             PlanetographicGrid* grid = new PlanetographicGrid(*body);
  340.             body->addReferenceMark(grid);
  341.         }
  342.     }
  343.     
  344.     return 0;
  345. }
  346. static int object_removereferencemark(lua_State* l)
  347. {
  348.     CelxLua celx(l);
  349.     celx.checkArgs(1, 1000, "Invalid number of arguments in object:removereferencemark");
  350.     CelestiaCore* appCore = celx.appCore(AllErrors);
  351.     
  352.     Selection* sel = this_object(l);
  353.     Body* body = sel->body();
  354.     
  355.     int argc = lua_gettop(l);
  356.     for (int i = 2; i <= argc; i++)
  357.     {
  358.         string refMark = celx.safeGetString(i, AllErrors, "Arguments to object:removereferencemark() must be strings");
  359.         
  360.         if (body->findReferenceMark(refMark))
  361.             appCore->toggleReferenceMark(refMark, *sel);
  362.     }
  363.     
  364.     return 0;
  365. }
  366. static int object_radius(lua_State* l)
  367. {
  368.     CelxLua celx(l);
  369.     celx.checkArgs(1, 1, "No arguments expected to function object:radius");
  370.     
  371.     Selection* sel = this_object(l);
  372.     lua_pushnumber(l, sel->radius());
  373.     
  374.     return 1;
  375. }
  376. static int object_setradius(lua_State* l)
  377. {
  378.     CelxLua celx(l);
  379.     celx.checkArgs(2, 2, "One argument expected to object:setradius()");
  380.     
  381.     Selection* sel = this_object(l);
  382.     if (sel->body() != NULL)
  383.     {
  384.         Body* body = sel->body();
  385.         float iradius = body->getRadius();
  386.         double radius = celx.safeGetNumber(2, AllErrors, "Argument to object:setradius() must be a number");
  387.         if ((radius > 0))
  388.         {
  389.             body->setSemiAxes(body->getSemiAxes() * ((float) radius / iradius));
  390.         }
  391.         
  392.         if (body->getRings() != NULL)
  393.         {
  394.             RingSystem rings(0.0f, 0.0f);
  395.             rings = *body->getRings();
  396.             float inner = rings.innerRadius;
  397.             float outer = rings.outerRadius;
  398.             rings.innerRadius = inner * (float) radius / iradius;
  399.             rings.outerRadius = outer * (float) radius / iradius;
  400.             body->setRings(rings);
  401.         }
  402.     }
  403.     
  404.     return 0;
  405. }
  406. static int object_type(lua_State* l)
  407. {
  408.     CelxLua celx(l);
  409.     celx.checkArgs(1, 1, "No arguments expected to function object:type");
  410.     
  411.     Selection* sel = this_object(l);
  412.     const char* tname = "unknown";
  413.     switch (sel->getType())
  414.     {
  415.         case Selection::Type_Body:
  416.         {
  417.             int cl = sel->body()->getClassification();
  418.             switch (cl)
  419.             {
  420.                 case Body::Planet : tname = "planet"; break;
  421.                 case Body::DwarfPlanet : tname = "dwarfplanet"; break;
  422.                 case Body::Moon : tname = "moon"; break;
  423.                 case Body::MinorMoon : tname = "minormoon"; break;
  424.                 case Body::Asteroid : tname = "asteroid"; break;
  425.                 case Body::Comet : tname = "comet"; break;
  426.                 case Body::Spacecraft : tname = "spacecraft"; break;
  427.                 case Body::Invisible : tname = "invisible"; break;
  428.                 case Body::SurfaceFeature : tname = "surfacefeature"; break;
  429.                 case Body::Component : tname = "component"; break;
  430.                 case Body::Diffuse : tname = "diffuse"; break;
  431.             }
  432.         }
  433.             break;
  434.             
  435.         case Selection::Type_Star:
  436.             tname = "star";
  437.             break;
  438.             
  439.         case Selection::Type_DeepSky:
  440.             tname = sel->deepsky()->getObjTypeName();
  441.             break;
  442.             
  443.         case Selection::Type_Location:
  444.             tname = "location";
  445.             break;
  446.             
  447.         case Selection::Type_Nil:
  448.             tname = "null";
  449.             break;
  450.     }
  451.     
  452.     lua_pushstring(l, tname);
  453.     
  454.     return 1;
  455. }
  456. static int object_name(lua_State* l)
  457. {
  458.     CelxLua celx(l);
  459.     celx.checkArgs(1, 1, "No arguments expected to function object:name");
  460.     
  461.     Selection* sel = this_object(l);
  462.     switch (sel->getType())
  463.     {
  464.         case Selection::Type_Body:
  465.             lua_pushstring(l, sel->body()->getName().c_str());
  466.             break;
  467.         case Selection::Type_DeepSky:
  468.             lua_pushstring(l, celx.appCore(AllErrors)->getSimulation()->getUniverse()
  469.                            ->getDSOCatalog()->getDSOName(sel->deepsky()).c_str());
  470.             break;
  471.         case Selection::Type_Star:
  472.             lua_pushstring(l, celx.appCore(AllErrors)->getSimulation()->getUniverse()
  473.                            ->getStarCatalog()->getStarName(*(sel->star())).c_str());
  474.             break;
  475.         case Selection::Type_Location:
  476.             lua_pushstring(l, sel->location()->getName().c_str());
  477.             break;
  478.         default:
  479.             lua_pushstring(l, "?");
  480.             break;
  481.     }
  482.     
  483.     return 1;
  484. }
  485. static int object_localname(lua_State* l)
  486. {
  487.     CelxLua celx(l);
  488.     celx.checkArgs(1, 1, "No arguments expected to function object:localname");
  489.     
  490.     Selection* sel = this_object(l);
  491.     switch (sel->getType())
  492.     {
  493.         case Selection::Type_Body:
  494.             lua_pushstring(l, sel->body()->getName(true).c_str());
  495.             break;
  496.         case Selection::Type_DeepSky:
  497.             lua_pushstring(l, celx.appCore(AllErrors)->getSimulation()->getUniverse()
  498.                            ->getDSOCatalog()->getDSOName(sel->deepsky(), true).c_str());
  499.             break;
  500.         case Selection::Type_Star:
  501.             lua_pushstring(l, celx.appCore(AllErrors)->getSimulation()->getUniverse()
  502.                            ->getStarCatalog()->getStarName(*(sel->star()), true).c_str());
  503.             break;
  504.         default:
  505.             lua_pushstring(l, "?");
  506.             break;
  507.     }
  508.     
  509.     return 1;
  510. }
  511. static int object_spectraltype(lua_State* l)
  512. {
  513.     CelxLua celx(l);
  514.     celx.checkArgs(1, 1, "No arguments expected to function object:spectraltype");
  515.     
  516.     Selection* sel = this_object(l);
  517.     if (sel->star() != NULL)
  518.     {
  519.         char buf[16];
  520.         strncpy(buf, sel->star()->getSpectralType(), sizeof buf);
  521.         buf[sizeof(buf) - 1] = ''; // make sure it's zero terminate
  522.         lua_pushstring(l, buf);
  523.     }
  524.     else
  525.     {
  526.         lua_pushnil(l);
  527.     }
  528.     
  529.     return 1;
  530. }
  531. static int object_getinfo(lua_State* l)
  532. {
  533.     CelxLua celx(l);
  534.     celx.checkArgs(1, 1, "No arguments expected to function object:getinfo");
  535.     
  536.     lua_newtable(l);
  537.     
  538.     Selection* sel = this_object(l);
  539.     if (sel->star() != NULL)
  540.     {
  541.         Star* star = sel->star();
  542.         celx.setTable("type", "star");
  543.         celx.setTable("name", celx.appCore(AllErrors)->getSimulation()->getUniverse()
  544.                  ->getStarCatalog()->getStarName(*(sel->star())).c_str());
  545.         celx.setTable("catalogNumber", star->getCatalogNumber());
  546.         celx.setTable("stellarClass", star->getSpectralType());
  547.         celx.setTable("absoluteMagnitude", (lua_Number)star->getAbsoluteMagnitude());
  548.         celx.setTable("luminosity", (lua_Number)star->getLuminosity());
  549.         celx.setTable("radius", (lua_Number)star->getRadius());
  550.         celx.setTable("temperature", (lua_Number)star->getTemperature());
  551.         celx.setTable("rotationPeriod", (lua_Number)star->getRotationModel()->getPeriod());
  552.         celx.setTable("bolometricMagnitude", (lua_Number)star->getBolometricMagnitude());
  553.         
  554.         if (star->getOrbitBarycenter() != NULL)
  555.         {
  556.             Selection parent((Star*)(star->getOrbitBarycenter()));
  557.             lua_pushstring(l, "parent");
  558.             object_new(l, parent);
  559.             lua_settable(l, -3);
  560.         }
  561.     }
  562.     else if (sel->body() != NULL)
  563.     {
  564.         Body* body = sel->body();
  565.         const char* tname = "unknown";
  566.         switch (body->getClassification())
  567.         {
  568.             case Body::Planet : tname = "planet"; break;
  569.             case Body::DwarfPlanet : tname = "dwarfplanet"; break;
  570.             case Body::Moon : tname = "moon"; break;
  571.             case Body::MinorMoon : tname = "minormoon"; break;
  572.             case Body::Asteroid : tname = "asteroid"; break;
  573.             case Body::Comet : tname = "comet"; break;
  574.             case Body::Spacecraft : tname = "spacecraft"; break;
  575.             case Body::Invisible : tname = "invisible"; break;
  576.             case Body::SurfaceFeature : tname = "surfacefeature"; break;
  577.             case Body::Component : tname = "component"; break;
  578.             case Body::Diffuse : tname = "diffuse"; break;
  579.         }
  580.         
  581.         celx.setTable("type", tname);
  582.         celx.setTable("name", body->getName().c_str());
  583.         celx.setTable("mass", (lua_Number)body->getMass());
  584.         celx.setTable("albedo", (lua_Number)body->getAlbedo());
  585.         celx.setTable("infoURL", body->getInfoURL().c_str());
  586.         celx.setTable("radius", (lua_Number)body->getRadius());
  587.         
  588.         // TODO: add method to return semiaxes
  589.         Vec3f semiAxes = body->getSemiAxes();
  590.         // Note: oblateness is an obsolete field, replaced by semiaxes;
  591.         // it's only here for backward compatibility.
  592.         float polarRadius = semiAxes.y;
  593.         float eqRadius = max(semiAxes.x, semiAxes.z);
  594.         celx.setTable("oblateness", (eqRadius - polarRadius) / eqRadius);
  595.         
  596.         double lifespanStart, lifespanEnd;
  597.         body->getLifespan(lifespanStart, lifespanEnd);
  598.         celx.setTable("lifespanStart", (lua_Number)lifespanStart);
  599.         celx.setTable("lifespanEnd", (lua_Number)lifespanEnd);
  600.         // TODO: atmosphere, surfaces ?
  601.         
  602.         PlanetarySystem* system = body->getSystem();
  603.         if (system->getPrimaryBody() != NULL)
  604.         {
  605.             Selection parent(system->getPrimaryBody());
  606.             lua_pushstring(l, "parent");
  607.             object_new(l, parent);
  608.             lua_settable(l, -3);
  609.         }
  610.         else
  611.         {
  612.             Selection parent(system->getStar());
  613.             lua_pushstring(l, "parent");
  614.             object_new(l, parent);
  615.             lua_settable(l, -3);
  616.         }
  617.         
  618.         lua_pushstring(l, "hasRings");
  619.         lua_pushboolean(l, body->getRings() != NULL);
  620.         lua_settable(l, -3);
  621.         
  622.         // TIMELINE-TODO: The code to retrieve orbital and rotation periods only works
  623.         // if the object has a single timeline phase. This should hardly ever
  624.         // be a problem, but it still may be best to set the periods to zero
  625.         // for objects with multiple phases.
  626.         const RotationModel* rm = body->getRotationModel(0.0);
  627.         celx.setTable("rotationPeriod", (double) rm->getPeriod());
  628.         
  629.         const Orbit* orbit = body->getOrbit(0.0);
  630.         celx.setTable("orbitPeriod", orbit->getPeriod());
  631.         Atmosphere* atmosphere = body->getAtmosphere();
  632.         if (atmosphere != NULL)
  633.         {
  634.             celx.setTable("atmosphereHeight", (double)atmosphere->height);
  635.             celx.setTable("atmosphereCloudHeight", (double)atmosphere->cloudHeight);
  636.             celx.setTable("atmosphereCloudSpeed", (double)atmosphere->cloudSpeed);
  637.         }
  638.     }
  639.     else if (sel->deepsky() != NULL)
  640.     {
  641.         DeepSkyObject* deepsky = sel->deepsky();
  642.         const char* objTypeName = deepsky->getObjTypeName();
  643.         celx.setTable("type", objTypeName);
  644.         
  645.         celx.setTable("name", celx.appCore(AllErrors)->getSimulation()->getUniverse()
  646.                  ->getDSOCatalog()->getDSOName(deepsky).c_str());
  647.         celx.setTable("catalogNumber", deepsky->getCatalogNumber());
  648.         
  649.         if (!strcmp(objTypeName, "galaxy"))
  650.             celx.setTable("hubbleType", deepsky->getType());
  651.         
  652.         celx.setTable("absoluteMagnitude", (lua_Number)deepsky->getAbsoluteMagnitude());
  653.         celx.setTable("radius", (lua_Number)deepsky->getRadius());
  654.     }
  655.     else if (sel->location() != NULL)
  656.     {
  657.         celx.setTable("type", "location");
  658.         Location* location = sel->location();
  659.         celx.setTable("name", location->getName().c_str());
  660.         celx.setTable("size", (lua_Number)location->getSize());
  661.         celx.setTable("importance", (lua_Number)location->getImportance());
  662.         celx.setTable("infoURL", location->getInfoURL().c_str());
  663.         
  664.         uint32 featureType = location->getFeatureType();
  665.         string featureName("Unknown");
  666.         for (CelxLua::FlagMap::const_iterator it = CelxLua::LocationFlagMap.begin();
  667.              it != CelxLua::LocationFlagMap.end(); it++)
  668.         {
  669.             if (it->second == featureType)
  670.             {
  671.                 featureName = it->first;
  672.                 break;
  673.             }
  674.         }
  675.         celx.setTable("featureType", featureName.c_str());
  676.         
  677.         Body* parent = location->getParentBody();
  678.         if (parent != NULL)
  679.         {
  680.             Selection selection(parent);
  681.             lua_pushstring(l, "parent");
  682.             object_new(l, selection);
  683.             lua_settable(l, -3);
  684.         }
  685.     }
  686.     else
  687.     {
  688.         celx.setTable("type", "null");
  689.     }
  690.     return 1;
  691. }
  692. static int object_absmag(lua_State* l)
  693. {
  694.     CelxLua celx(l);
  695.     celx.checkArgs(1, 1, "No arguments expected to function object:absmag");
  696.     
  697.     Selection* sel = this_object(l);
  698.     if (sel->star() != NULL)
  699.         lua_pushnumber(l, sel->star()->getAbsoluteMagnitude());
  700.     else
  701.         lua_pushnil(l);
  702.     
  703.     return 1;
  704. }
  705. static int object_mark(lua_State* l)
  706. {
  707.     CelxLua celx(l);
  708.     celx.checkArgs(1, 7, "Need 0 to 6 arguments for object:mark");
  709.     
  710.     Selection* sel = this_object(l);
  711.     CelestiaCore* appCore = celx.appCore(AllErrors);
  712.     
  713.     Color markColor(0.0f, 1.0f, 0.0f);
  714.     const char* colorString = celx.safeGetString(2, WrongType, "First argument to object:mark must be a string");
  715.     if (colorString != NULL)
  716.         Color::parse(colorString, markColor);
  717.     
  718.     MarkerRepresentation::Symbol markSymbol = MarkerRepresentation::Diamond;
  719.     const char* markerString = celx.safeGetString(3, WrongType, "Second argument to object:mark must be a string");
  720.     if (markerString != NULL)
  721.         markSymbol = parseMarkerSymbol(markerString);
  722.     
  723.     float markSize = (float)celx.safeGetNumber(4, WrongType, "Third arg to object:mark must be a number", 10.0);
  724.     if (markSize < 1.0f)
  725.         markSize = 1.0f;
  726.     else if (markSize > 10000.0f)
  727.         markSize = 10000.0f;
  728.     
  729.     float markAlpha = (float)celx.safeGetNumber(5, WrongType, "Fourth arg to object:mark must be a number", 0.9);
  730.     if (markAlpha < 0.0f)
  731.         markAlpha = 0.0f;
  732.     else if (markAlpha > 1.0f)
  733.         markAlpha = 1.0f;
  734.     
  735.     Color markColorAlpha(0.0f, 1.0f, 0.0f, 0.9f);
  736.     markColorAlpha = Color::Color(markColor, markAlpha);
  737.     
  738.     const char* markLabel = celx.safeGetString(6, WrongType, "Fifth argument to object:mark must be a string");
  739.     if (markLabel == NULL)
  740.         markLabel = "";
  741.     
  742.     bool occludable = celx.safeGetBoolean(7, WrongType, "Sixth argument to object:mark must be a boolean", true);
  743.     
  744.     Simulation* sim = appCore->getSimulation();
  745.     
  746.     MarkerRepresentation markerRep(markSymbol);
  747.     markerRep.setSize(markSize);
  748.     markerRep.setColor(markColorAlpha);
  749.     markerRep.setLabel(markLabel);
  750.     sim->getUniverse()->markObject(*sel, markerRep, 1, occludable);
  751.     
  752.     return 0;
  753. }
  754. static int object_unmark(lua_State* l)
  755. {
  756.     CelxLua celx(l);
  757.     celx.checkArgs(1, 1, "No arguments expected to function object:unmark");
  758.     
  759.     Selection* sel = this_object(l);
  760.     CelestiaCore* appCore = celx.appCore(AllErrors);
  761.     
  762.     Simulation* sim = appCore->getSimulation();
  763.     sim->getUniverse()->unmarkObject(*sel, 1);
  764.     
  765.     return 0;
  766. }
  767. // Return the object's current position.  A time argument is optional;
  768. // if not provided, the current master simulation time is used.
  769. static int object_getposition(lua_State* l)
  770. {
  771.     CelxLua celx(l);
  772.     celx.checkArgs(1, 2, "Expected no or one argument to object:getposition");
  773.     
  774.     Selection* sel = this_object(l);
  775.     CelestiaCore* appCore = celx.appCore(AllErrors);
  776.     
  777.     double t = celx.safeGetNumber(2, WrongType, "Time expected as argument to object:getposition",
  778.                                   appCore->getSimulation()->getTime());
  779.     celx.newPosition(sel->getPosition(t));
  780.     
  781.     return 1;
  782. }
  783. static int object_getchildren(lua_State* l)
  784. {
  785.     CelxLua celx(l);
  786.     celx.checkArgs(1, 1, "No arguments expected for object:getchildren()");
  787.     
  788.     Selection* sel = this_object(l);
  789.     CelestiaCore* appCore = celx.appCore(AllErrors);
  790.     
  791.     Simulation* sim = appCore->getSimulation();
  792.     
  793.     lua_newtable(l);
  794.     if (sel->star() != NULL)
  795.     {
  796.         SolarSystemCatalog* solarSystemCatalog = sim->getUniverse()->getSolarSystemCatalog();
  797.         SolarSystemCatalog::iterator iter = solarSystemCatalog->find(sel->star()->getCatalogNumber());
  798.         if (iter != solarSystemCatalog->end())
  799.         {
  800.             SolarSystem* solarSys = iter->second;
  801.             for (int i = 0; i < solarSys->getPlanets()->getSystemSize(); i++)
  802.             {
  803.                 Body* body = solarSys->getPlanets()->getBody(i);
  804.                 Selection satSel(body);
  805.                 object_new(l, satSel);
  806.                 lua_rawseti(l, -2, i + 1);
  807.             }
  808.         }
  809.     }
  810.     else if (sel->body() != NULL)
  811.     {
  812.         const PlanetarySystem* satellites = sel->body()->getSatellites();
  813.         if (satellites != NULL && satellites->getSystemSize() != 0)
  814.         {
  815.             for (int i = 0; i < satellites->getSystemSize(); i++)
  816.             {
  817.                 Body* body = satellites->getBody(i);
  818.                 Selection satSel(body);
  819.                 object_new(l, satSel);
  820.                 lua_rawseti(l, -2, i + 1);
  821.             }
  822.         }
  823.     }
  824.     
  825.     return 1;
  826. }
  827. static int object_preloadtexture(lua_State* l)
  828. {
  829.     CelxLua celx(l);
  830.     celx.checkArgs(1, 1, "No argument expected to object:preloadtexture");
  831.     CelestiaCore* appCore = celx.appCore(AllErrors);
  832.     
  833.     Renderer* renderer = appCore->getRenderer();
  834.     Selection* sel = this_object(l);
  835.     if (sel->body() != NULL && renderer != NULL)
  836.     {
  837.         LuaState* luastate = celx.getLuaStateObject();
  838.         // make sure we don't timeout because of texture-loading:
  839.         double timeToTimeout = luastate->timeout - luastate->getTime();
  840.         
  841.         renderer->loadTextures(sel->body());
  842.         
  843.         // no matter how long it really took, make it look like 0.1s:
  844.         luastate->timeout = luastate->getTime() + timeToTimeout - 0.1;
  845.     }
  846.     return 0;
  847. }
  848. /*! object:catalognumber(string: catalog_prefix)
  849. *
  850. *  Look up the catalog number for a star in one of the supported catalogs,
  851. *  currently HIPPARCOS, HD, or SAO. The single argument is a string that
  852. *  specifies the catalog number, either "HD", "SAO", or "HIP".
  853. *  If the object is a star, the catalog string is valid, and the star
  854. *  is present in the catalog, the catalog number is returned on the stack.
  855. *  Otherwise, nil is returned.
  856. *
  857. * verbatim
  858. * -- Example: Get the SAO and HD catalog numbers for Rigel
  859. * --
  860. * rigel = celestia:find("Rigel")
  861. * sao = rigel:catalognumber("SAO")
  862. * hd = rigel:catalognumber("HD")
  863. *
  864. * endverbatim
  865. */
  866. static int object_catalognumber(lua_State* l)
  867. {
  868.     CelxLua celx(l);
  869. celx.checkArgs(2, 2, "One argument expected to object:catalognumber");
  870. CelestiaCore* appCore = celx.appCore(AllErrors);
  871.     
  872. Selection* sel = this_object(l);
  873.     const char* catalogName = celx.safeGetString(2, WrongType, "Argument to object:catalognumber must be a string");
  874.     
  875. // The argument is a string indicating the catalog.
  876. bool validCatalog = false;
  877. bool useHIPPARCOS = false;
  878. StarDatabase::Catalog catalog = StarDatabase::HenryDraper;
  879. if (catalogName != NULL)
  880. {
  881. if (compareIgnoringCase(catalogName, "HD") == 0)
  882. {
  883. catalog = StarDatabase::HenryDraper;
  884. validCatalog = true;
  885. }
  886. else if (compareIgnoringCase(catalogName, "SAO") == 0)
  887. {
  888. catalog = StarDatabase::SAO;
  889. validCatalog = true;
  890. }
  891. else if (compareIgnoringCase(catalogName, "HIP") == 0)
  892. {
  893. useHIPPARCOS = true;
  894. validCatalog = true;
  895. }
  896. }
  897.     
  898. uint32 catalogNumber = Star::InvalidCatalogNumber;
  899. if (sel->star() != NULL && validCatalog)
  900. {
  901. uint32 internalNumber = sel->star()->getCatalogNumber();
  902.         
  903. if (useHIPPARCOS)
  904. {
  905. // Celestia's internal catalog numbers /are/ HIPPARCOS numbers
  906. if (internalNumber < StarDatabase::MAX_HIPPARCOS_NUMBER)
  907. catalogNumber = internalNumber;
  908. }
  909. else
  910. {
  911. const StarDatabase* stardb = appCore->getSimulation()->getUniverse()->getStarCatalog();
  912. catalogNumber = stardb->crossIndex(catalog, internalNumber);
  913. }
  914. }
  915.     
  916. if (catalogNumber != Star::InvalidCatalogNumber)
  917. lua_pushnumber(l, catalogNumber);
  918. else
  919. lua_pushnil(l);
  920.     
  921. return 1;
  922. }
  923. // Locations iterator function; two upvalues expected. Used by
  924. // object:locations method.
  925. static int object_locations_iter(lua_State* l)
  926. {
  927.     CelxLua celx(l);
  928.     Selection* sel = to_object(l, lua_upvalueindex(1));
  929.     if (sel == NULL)
  930.     {
  931.         celx.doError("Bad object!");
  932.         return 0;
  933.     }
  934.     
  935.     // Get the current counter value
  936.     uint32 i = (uint32) lua_tonumber(l, lua_upvalueindex(2));
  937.     
  938.     vector<Location*>* locations = NULL;
  939.     if (sel->body() != NULL)
  940.     {
  941.         locations = sel->body()->getLocations();
  942.     }
  943.     
  944.     if (locations != NULL && i < locations->size())
  945.     {
  946.         // Increment the counter
  947.         lua_pushnumber(l, i + 1);
  948.         lua_replace(l, lua_upvalueindex(2));
  949.         
  950.         Location* loc = locations->at(i);
  951.         if (loc == NULL)
  952.             lua_pushnil(l);
  953.         else
  954.             object_new(l, Selection(loc));
  955.         
  956.         return 1;
  957.     }
  958.     else
  959.     {
  960.         // Return nil when we've enumerated all the locations (or if
  961.         // there were no locations associated with the object.)
  962.         return 0;
  963.     }
  964. }
  965. /*! object:locations()
  966. *
  967. * Return an iterator over all the locations associated with an object.
  968. * Only solar system bodies have locations; for all other object types,
  969. * this method will return an empty iterator.
  970. *
  971. * verbatim
  972. * -- Example: print locations of current selection
  973. * --
  974. * for loc in celestia:getselection():locations() do
  975. *     celestia:log(loc:name())
  976. * end
  977. *
  978. * endverbatim
  979. */
  980. static int object_locations(lua_State* l)
  981. {
  982.     CelxLua celx(l);
  983.     // Push a closure with two upvalues: the object and a counter
  984.     lua_pushvalue(l, 1);    // object
  985.     lua_pushnumber(l, 0);   // counter
  986.     lua_pushcclosure(l, object_locations_iter, 2);
  987.     
  988.     return 1;
  989. }
  990. /*! object:bodyfixedframe()
  991. *
  992. * Return the body-fixed frame for this object.
  993. *
  994. * verbatim
  995. * -- Example: get the body-fixed frame of the Earth
  996. * --
  997. * earth = celestia:find("Sol/Earth")
  998. * ebf = earth:bodyfixedframe()
  999. *
  1000. * endverbatim
  1001. */
  1002. static int object_bodyfixedframe(lua_State* l)
  1003. {
  1004.     CelxLua celx(l);
  1005. celx.checkArgs(1, 1, "No arguments allowed for object:bodyfixedframe");
  1006.     
  1007. Selection* sel = this_object(l);    
  1008.     celx.newFrame(ObserverFrame(ObserverFrame::BodyFixed, *sel));
  1009.     
  1010.     return 1;
  1011. }
  1012. /*! object:equatorialframe()
  1013. *
  1014. * Return the mean equatorial frame for this object.
  1015. *
  1016. * verbatim
  1017. * -- Example: getthe equatorial frame of the Earth
  1018. * --
  1019. * earth = celestia:find("Sol/Earth")
  1020. * eme = earth:equatorialframe()
  1021. *
  1022. * endverbatim
  1023. */
  1024. static int object_equatorialframe(lua_State* l)
  1025. {
  1026.     // TODO: allow one argument specifying a freeze time
  1027.     CelxLua celx(l);
  1028. celx.checkArgs(1, 1, "No arguments allowed for to object:equatorialframe");
  1029.     
  1030. Selection* sel = this_object(l);    
  1031.     celx.newFrame(ObserverFrame(ObserverFrame::Equatorial, *sel));
  1032.     
  1033.     return 1;
  1034. }
  1035. /*! object:orbitframe(time: t)
  1036. *
  1037. * Return the frame in which the orbit for an object is defined at a particular
  1038. * time. If time isn't specified, the current simulation time is assumed. The
  1039. * positions of stars and deep sky objects are always defined in the universal
  1040. * frame.
  1041. *
  1042. * verbatim
  1043. * -- Example: get the orbital frame for the Earth at the current time.
  1044. * --
  1045. * earth = celestia:find("Sol/Earth")
  1046. * eof = earth:orbitframe() 
  1047. *
  1048. * endverbatim
  1049. */
  1050. static int object_orbitframe(lua_State* l)
  1051. {
  1052.     CelxLua celx(l);
  1053. celx.checkArgs(1, 2, "One or no arguments allowed for to object:orbitframe");
  1054.     
  1055. Selection* sel = this_object(l);
  1056.     CelestiaCore* appCore = celx.appCore(AllErrors);
  1057.     
  1058.     double t = celx.safeGetNumber(2, WrongType, "Time expected as argument to object:orbitframe",
  1059.                                   appCore->getSimulation()->getTime());
  1060.     
  1061.     if (sel->body() == NULL)
  1062.     {
  1063.         // The default universal frame
  1064.         celx.newFrame(ObserverFrame());
  1065.     }
  1066.     else 
  1067.     {
  1068.         const ReferenceFrame* f = sel->body()->getOrbitFrame(t);
  1069.         celx.newFrame(ObserverFrame(*f));
  1070.     }
  1071.     
  1072.     return 1;
  1073. }
  1074. /*! object:bodyframe(time: t)
  1075. *
  1076. * Return the frame in which the orientation for an object is defined at a 
  1077. * particular time. If time isn't specified, the current simulation time is
  1078. * assumed. The positions of stars and deep sky objects are always defined
  1079. * in the universal frame.
  1080. *
  1081. * verbatim
  1082. * -- Example: get the curren body frame for the International Space Station.
  1083. * --
  1084. * iss = celestia:find("Sol/Earth/ISS")
  1085. * f = iss:bodyframe() 
  1086. *
  1087. * endverbatim
  1088. */
  1089. static int object_bodyframe(lua_State* l)
  1090. {
  1091.     CelxLua celx(l);
  1092. celx.checkArgs(1, 2, "One or no arguments allowed for to object:bodyframe");
  1093.     
  1094. Selection* sel = this_object(l);
  1095.     CelestiaCore* appCore = celx.appCore(AllErrors);
  1096.     
  1097.     double t = celx.safeGetNumber(2, WrongType, "Time expected as argument to object:orbitframe",
  1098.                                   appCore->getSimulation()->getTime());
  1099.     
  1100.     if (sel->body() == NULL)
  1101.     {
  1102.         // The default universal frame
  1103.         celx.newFrame(ObserverFrame());
  1104.     }
  1105.     else 
  1106.     {
  1107.         const ReferenceFrame* f = sel->body()->getBodyFrame(t);
  1108.         celx.newFrame(ObserverFrame(*f));
  1109.     }
  1110.     
  1111.     return 1;
  1112. }
  1113. /*! object:getphase(time: t)
  1114. *
  1115. * Get the active timeline phase at the specified time. If no time is
  1116. * specified, the current simulation time is used. This method returns
  1117. * nil if the object is not a solar system body, or if the time lies
  1118. * outside the range covered by the timeline.
  1119. *
  1120. * verbatim
  1121. * -- Example: get the timeline phase for Cassini at midnight January 1, 2000 UTC.
  1122. * --
  1123. * cassini = celestia:find("Sol/Cassini")
  1124. * tdb = celestia:utctotdb(2000, 1, 1)
  1125. * phase = cassini:getphase(tdb)
  1126. *
  1127. * endverbatim
  1128. */
  1129. static int object_getphase(lua_State* l)
  1130. {
  1131.     CelxLua celx(l);
  1132. celx.checkArgs(1, 2, "One or no arguments allowed for to object:getphase");
  1133.     
  1134. Selection* sel = this_object(l);
  1135.     CelestiaCore* appCore = celx.appCore(AllErrors);
  1136.     
  1137.     double t = celx.safeGetNumber(2, WrongType, "Time expected as argument to object:getphase",
  1138.                                   appCore->getSimulation()->getTime());
  1139.     
  1140.     if (sel->body() == NULL)
  1141.     {
  1142.         lua_pushnil(l);
  1143.     }
  1144.     else 
  1145.     {
  1146.         const Timeline* timeline = sel->body()->getTimeline();
  1147.         if (timeline->includes(t))
  1148.         {
  1149.             celx.newPhase(*timeline->findPhase(t));
  1150.         }
  1151.         else
  1152.         {
  1153.             lua_pushnil(l);
  1154.         }
  1155.     }
  1156.     
  1157.     return 1;
  1158. }
  1159. // Phases iterator function; two upvalues expected. Used by
  1160. // object:phases method.
  1161. static int object_phases_iter(lua_State* l)
  1162. {
  1163.     CelxLua celx(l);
  1164.     Selection* sel = to_object(l, lua_upvalueindex(1));
  1165.     if (sel == NULL)
  1166.     {
  1167.         celx.doError("Bad object!");
  1168.         return 0;
  1169.     }
  1170.     
  1171.     // Get the current counter value
  1172.     uint32 i = (uint32) lua_tonumber(l, lua_upvalueindex(2));
  1173.     
  1174.     const Timeline* timeline = NULL;
  1175.     if (sel->body() != NULL)
  1176.     {
  1177.         timeline = sel->body()->getTimeline();
  1178.     }
  1179.     
  1180.     if (timeline != NULL && i < timeline->phaseCount())
  1181.     {
  1182.         // Increment the counter
  1183.         lua_pushnumber(l, i + 1);
  1184.         lua_replace(l, lua_upvalueindex(2));
  1185.         
  1186.         const TimelinePhase* phase = timeline->getPhase(i);
  1187.         celx.newPhase(*phase);
  1188.         
  1189.         return 1;
  1190.     }
  1191.     else
  1192.     {
  1193.         // Return nil when we've enumerated all the phases (or if
  1194.         // if the object wasn't a solar system body.)
  1195.         return 0;
  1196.     }
  1197. }
  1198. /*! object:phases()
  1199. *
  1200. * Return an iterator over all the phases in an object's timeline.
  1201. * Only solar system bodies have timeline; for all other object types,
  1202. * this method will return an empty iterator. The phases in a timeline
  1203. * are always sorted from earliest to latest, and always coverage a
  1204. * continuous span of time.
  1205. *
  1206. * verbatim
  1207. * -- Example: copy all of an objects phases into the array timeline
  1208. * --
  1209. * timeline = { }
  1210. * count = 0
  1211. * for phase in celestia:getselection():phases() do
  1212. *     count = count + 1
  1213. *     timeline[count] = phase
  1214. * end
  1215. *
  1216. * endverbatim
  1217. */
  1218. static int object_phases(lua_State* l)
  1219. {
  1220.     CelxLua celx(l);
  1221.     // Push a closure with two upvalues: the object and a counter
  1222.     lua_pushvalue(l, 1);    // object
  1223.     lua_pushnumber(l, 0);   // counter
  1224.     lua_pushcclosure(l, object_phases_iter, 2);
  1225.     
  1226.     return 1;
  1227. }
  1228. void CreateObjectMetaTable(lua_State* l)
  1229. {
  1230.     CelxLua celx(l);
  1231.     
  1232.     celx.createClassMetatable(Celx_Object);
  1233.     celx.registerMethod("__tostring", object_tostring);
  1234.     celx.registerMethod("visible", object_visible);
  1235.     celx.registerMethod("setvisible", object_setvisible);
  1236.     celx.registerMethod("orbitcoloroverridden", object_orbitcoloroverridden);
  1237.     celx.registerMethod("setorbitcoloroverridden", object_setorbitcoloroverridden);
  1238.     celx.registerMethod("setorbitcolor", object_setorbitcolor);
  1239.     celx.registerMethod("orbitvisibility", object_orbitvisibility);
  1240.     celx.registerMethod("setorbitvisibility", object_setorbitvisibility);
  1241.     celx.registerMethod("addreferencemark", object_addreferencemark);
  1242.     celx.registerMethod("removereferencemark", object_removereferencemark);
  1243.     celx.registerMethod("radius", object_radius);
  1244.     celx.registerMethod("setradius", object_setradius);
  1245.     celx.registerMethod("type", object_type);
  1246.     celx.registerMethod("spectraltype", object_spectraltype);
  1247.     celx.registerMethod("getinfo", object_getinfo);
  1248.     celx.registerMethod("catalognumber", object_catalognumber);
  1249.     celx.registerMethod("absmag", object_absmag);
  1250.     celx.registerMethod("name", object_name);
  1251.     celx.registerMethod("localname", object_localname);
  1252.     celx.registerMethod("mark", object_mark);
  1253.     celx.registerMethod("unmark", object_unmark);
  1254.     celx.registerMethod("getposition", object_getposition);
  1255.     celx.registerMethod("getchildren", object_getchildren);
  1256.     celx.registerMethod("locations", object_locations);
  1257.     celx.registerMethod("bodyfixedframe", object_bodyfixedframe);
  1258.     celx.registerMethod("equatorialframe", object_equatorialframe);
  1259.     celx.registerMethod("orbitframe", object_orbitframe);
  1260.     celx.registerMethod("bodyframe", object_bodyframe);
  1261.     celx.registerMethod("getphase", object_getphase);
  1262.     celx.registerMethod("phases", object_phases);
  1263.     celx.registerMethod("preloadtexture", object_preloadtexture);
  1264.     
  1265.     lua_pop(l, 1); // pop metatable off the stack
  1266. }
  1267. // ==================== object extensions ====================
  1268. // TODO: This should be replaced by an actual Atmosphere object
  1269. static int object_setatmosphere(lua_State* l)
  1270. {
  1271.     CelxLua celx(l);
  1272.     celx.checkArgs(23, 23, "22 arguments (!) expected to function object:setatmosphere");
  1273.     
  1274.     Selection* sel = this_object(l);
  1275.     //CelestiaCore* appCore = getAppCore(l, AllErrors);
  1276.     
  1277.     if (sel->body() != NULL)
  1278.     {
  1279.         Body* body = sel->body();
  1280.         Atmosphere* atmosphere = body->getAtmosphere();
  1281.         if (atmosphere != NULL)
  1282.         {
  1283.             float r = (float) celx.safeGetNumber(2, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1284.             float g = (float) celx.safeGetNumber(3, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1285.             float b = (float) celx.safeGetNumber(4, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1286.             // Color testColor(0.0f, 1.0f, 0.0f);
  1287.             Color testColor(r, g, b);
  1288.             atmosphere->lowerColor = testColor;
  1289.             r = (float) celx.safeGetNumber(5, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1290.             g = (float) celx.safeGetNumber(6, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1291.             b = (float) celx.safeGetNumber(7, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1292.             atmosphere->upperColor = Color(r, g, b);
  1293.             r = (float) celx.safeGetNumber(8, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1294.             g = (float) celx.safeGetNumber(9, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1295.             b = (float) celx.safeGetNumber(10, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1296.             atmosphere->skyColor = Color(r, g, b);
  1297.             r = (float) celx.safeGetNumber(11, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1298.             g = (float) celx.safeGetNumber(12, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1299.             b = (float) celx.safeGetNumber(13, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1300.             atmosphere->sunsetColor = Color(r, g, b);
  1301.             r = (float) celx.safeGetNumber(14, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1302.             g = (float) celx.safeGetNumber(15, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1303.             b = (float) celx.safeGetNumber(16, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1304.             //HWR atmosphere->rayleighCoeff = Vector3(r, g, b);
  1305.             r = (float) celx.safeGetNumber(17, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1306.             g = (float) celx.safeGetNumber(18, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1307.             b = (float) celx.safeGetNumber(19, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1308.             //HWR atmosphere->absorptionCoeff = Vector3(r, g, b);
  1309.             b = (float) celx.safeGetNumber(20, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1310.             atmosphere->mieCoeff = b;
  1311.             b = (float) celx.safeGetNumber(21, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1312.             atmosphere->mieScaleHeight = b;
  1313.             b = (float) celx.safeGetNumber(22, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1314.             atmosphere->miePhaseAsymmetry = b;
  1315.             b = (float) celx.safeGetNumber(23, AllErrors, "Arguments to observer:setatmosphere() must be numbers");
  1316.             atmosphere->rayleighScaleHeight = b;
  1317.             
  1318.             body->setAtmosphere(*atmosphere);
  1319.             cout << "set atmospheren";
  1320.         }
  1321.     }
  1322.     
  1323.     return 0;
  1324. }
  1325. void ExtendObjectMetaTable(lua_State* l)
  1326. {
  1327.     CelxLua celx(l);
  1328.     celx.pushClassName(Celx_Object);
  1329.     lua_rawget(l, LUA_REGISTRYINDEX);
  1330.     if (lua_type(l, -1) != LUA_TTABLE)
  1331.         cout << "Metatable for " << CelxLua::ClassNames[Celx_Object] << " not found!n";
  1332.     celx.registerMethod("setatmosphere", object_setatmosphere);
  1333. lua_pop(l, 1);
  1334. }