00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <cassert>
00013 #include <cstring>
00014 #include <cstdio>
00015 #include <map>
00016 #include <celengine/astro.h>
00017 #include <celengine/celestia.h>
00018 #include <celengine/cmdparser.h>
00019 #include <celengine/execenv.h>
00020 #include <celengine/execution.h>
00021 #include <celmath/vecmath.h>
00022 #include <celengine/gl.h>
00023 #include "imagecapture.h"
00024
00025
00026
00027 #ifdef HAVE_SSTREAM
00028 #include <sstream>
00029 #else
00030 #include <strstream>
00031 #endif // HAVE_SSTREAM
00032
00033 #include "celx.h"
00034 #include "celestiacore.h"
00035 extern "C" {
00036 #include "lualib.h"
00037 }
00038
00039 using namespace std;
00040
00041 static const char* ClassNames[] =
00042 {
00043 "class_celestia",
00044 "class_observer",
00045 "class_object",
00046 "class_vec3",
00047 "class_matrix",
00048 "class_rotation",
00049 "class_position",
00050 "class_frame",
00051 "class_celscript",
00052 };
00053
00054 static const int _Celestia = 0;
00055 static const int _Observer = 1;
00056 static const int _Object = 2;
00057 static const int _Vec3 = 3;
00058 static const int _Matrix = 4;
00059 static const int _Rotation = 5;
00060 static const int _Position = 6;
00061 static const int _Frame = 7;
00062 static const int _CelScript= 8;
00063
00064 #define CLASS(i) ClassNames[(i)]
00065
00066
00067
00068 static const double MaxTimeslice = 5.0;
00069
00070
00071 static const char* KbdCallback = "celestia_keyboard_callback";
00072 static const char* CleanupCallback = "celestia_cleanup_callback";
00073
00074 typedef map<string, uint32> FlagMap;
00075
00076 static FlagMap RenderFlagMap;
00077 static FlagMap LabelFlagMap;
00078 static FlagMap LocationFlagMap;
00079 static FlagMap BodyTypeMap;
00080 static bool mapsInitialized = false;
00081
00082
00083
00084 enum FatalErrors {
00085 NoErrors = 0,
00086 WrongType = 1,
00087 WrongArgc = 2,
00088 AllErrors = WrongType | WrongArgc,
00089 };
00090
00091
00092
00093 static void initRenderFlagMap()
00094 {
00095 RenderFlagMap["orbits"] = Renderer::ShowOrbits;
00096 RenderFlagMap["cloudmaps"] = Renderer::ShowCloudMaps;
00097 RenderFlagMap["constellations"] = Renderer::ShowDiagrams;
00098 RenderFlagMap["galaxies"] = Renderer::ShowGalaxies;
00099 RenderFlagMap["planets"] = Renderer::ShowPlanets;
00100 RenderFlagMap["stars"] = Renderer::ShowStars;
00101 RenderFlagMap["nightmaps"] = Renderer::ShowNightMaps;
00102 RenderFlagMap["eclipseshadows"] = Renderer::ShowEclipseShadows;
00103 RenderFlagMap["ringshadows"] = Renderer::ShowRingShadows;
00104 RenderFlagMap["comettails"] = Renderer::ShowCometTails;
00105 RenderFlagMap["boundaries"] = Renderer::ShowBoundaries;
00106 RenderFlagMap["markers"] = Renderer::ShowMarkers;
00107 RenderFlagMap["automag"] = Renderer::ShowAutoMag;
00108 RenderFlagMap["atmospheres"] = Renderer::ShowAtmospheres;
00109 RenderFlagMap["grid"] = Renderer::ShowCelestialSphere;
00110 RenderFlagMap["smoothlines"] = Renderer::ShowSmoothLines;
00111 RenderFlagMap["partialtrajectories"] = Renderer::ShowPartialTrajectories;
00112 }
00113
00114 static void initLabelFlagMap()
00115 {
00116 LabelFlagMap["planets"] = Renderer::PlanetLabels;
00117 LabelFlagMap["moons"] = Renderer::MoonLabels;
00118 LabelFlagMap["spacecraft"] = Renderer::SpacecraftLabels;
00119 LabelFlagMap["asteroids"] = Renderer::AsteroidLabels;
00120 LabelFlagMap["comets"] = Renderer::CometLabels;
00121 LabelFlagMap["constellations"] = Renderer::ConstellationLabels;
00122 LabelFlagMap["stars"] = Renderer::StarLabels;
00123 LabelFlagMap["galaxies"] = Renderer::GalaxyLabels;
00124 LabelFlagMap["locations"] = Renderer::LocationLabels;
00125 }
00126
00127 static void initBodyTypeMap()
00128 {
00129 BodyTypeMap["Planet"] = Body::Planet;
00130 BodyTypeMap["Moon"] = Body::Moon;
00131 BodyTypeMap["Asteroid"] = Body::Asteroid;
00132 BodyTypeMap["Comet"] = Body::Comet;
00133 BodyTypeMap["Spacecraft"] = Body::Spacecraft;
00134 BodyTypeMap["Invisible"] = Body::Invisible;
00135 BodyTypeMap["Unknown"] = Body::Unknown;
00136 }
00137
00138 static void initLocationFlagMap()
00139 {
00140 LocationFlagMap["city"] = Location::City;
00141 LocationFlagMap["observatory"] = Location::Observatory;
00142 LocationFlagMap["landingsite"] = Location::LandingSite;
00143 LocationFlagMap["crater"] = Location::Crater;
00144 LocationFlagMap["vallis"] = Location::Vallis;
00145 LocationFlagMap["mons"] = Location::Mons;
00146 LocationFlagMap["planum"] = Location::Planum;
00147 LocationFlagMap["chasma"] = Location::Chasma;
00148 LocationFlagMap["patera"] = Location::Patera;
00149 LocationFlagMap["mare"] = Location::Mare;
00150 LocationFlagMap["rupes"] = Location::Rupes;
00151 LocationFlagMap["tessera"] = Location::Tessera;
00152 LocationFlagMap["regio"] = Location::Regio;
00153 LocationFlagMap["chaos"] = Location::Chaos;
00154 LocationFlagMap["terra"] = Location::Terra;
00155 LocationFlagMap["astrum"] = Location::Astrum;
00156 LocationFlagMap["corona"] = Location::Corona;
00157 LocationFlagMap["dorsum"] = Location::Dorsum;
00158 LocationFlagMap["fossa"] = Location::Fossa;
00159 LocationFlagMap["catena"] = Location::Catena;
00160 LocationFlagMap["mensa"] = Location::Mensa;
00161 LocationFlagMap["rima"] = Location::Rima;
00162 LocationFlagMap["undae"] = Location::Undae;
00163 LocationFlagMap["reticulum"] = Location::Reticulum;
00164 LocationFlagMap["planitia"] = Location::Planitia;
00165 LocationFlagMap["linea"] = Location::Linea;
00166 LocationFlagMap["fluctus"] = Location::Fluctus;
00167 LocationFlagMap["farrum"] = Location::Farrum;
00168 LocationFlagMap["other"] = Location::Other;
00169 }
00170
00171 static void initMaps()
00172 {
00173 if (!mapsInitialized)
00174 {
00175 initRenderFlagMap();
00176 initLabelFlagMap();
00177 initBodyTypeMap();
00178 initLocationFlagMap();
00179 }
00180 mapsInitialized = true;
00181 }
00182
00183
00184
00185 class CelScriptWrapper : public ExecutionEnvironment
00186 {
00187 public:
00188 CelScriptWrapper(CelestiaCore& appCore, istream& scriptfile):
00189 script(NULL),
00190 core(appCore),
00191 cmdSequence(NULL),
00192 tickTime(0.0),
00193 errorMessage("")
00194 {
00195 CommandParser parser(scriptfile);
00196 cmdSequence = parser.parse();
00197 if (cmdSequence != NULL)
00198 {
00199 script = new Execution(*cmdSequence, *this);
00200 }
00201 else
00202 {
00203 const vector<string>* errors = parser.getErrors();
00204 if (errors->size() > 0)
00205 errorMessage = "Error while parsing CEL-script: " + (*errors)[0];
00206 else
00207 errorMessage = "Error while parsing CEL-script.";
00208 }
00209 }
00210
00211 virtual ~CelScriptWrapper()
00212 {
00213 if (script != NULL)
00214 delete script;
00215 if (cmdSequence != NULL)
00216 delete cmdSequence;
00217 }
00218
00219 string getErrorMessage() const
00220 {
00221 return errorMessage;
00222 }
00223
00224
00225 bool tick(double t)
00226 {
00227
00228 if (tickTime == 0.0)
00229 {
00230 tickTime = t;
00231 return false;
00232 }
00233 double dt = t - tickTime;
00234 tickTime = t;
00235 return script->tick(dt);
00236 }
00237
00238 Simulation* getSimulation() const
00239 {
00240 return core.getSimulation();
00241 }
00242
00243 Renderer* getRenderer() const
00244 {
00245 return core.getRenderer();
00246 }
00247
00248 CelestiaCore* getCelestiaCore() const
00249 {
00250 return &core;
00251 }
00252
00253 void showText(string s, int horig, int vorig, int hoff, int voff,
00254 double duration)
00255 {
00256 core.showText(s, horig, vorig, hoff, voff, duration);
00257 }
00258
00259 private:
00260 Execution* script;
00261 CelestiaCore& core;
00262 CommandSequence* cmdSequence;
00263 double tickTime;
00264 string errorMessage;
00265 };
00266
00267
00268
00269 static void PushClass(lua_State* l, int id)
00270 {
00271 lua_pushlstring(l, ClassNames[id], strlen(ClassNames[id]));
00272 }
00273
00274
00275 static void SetClass(lua_State* l, int id)
00276 {
00277 PushClass(l, id);
00278 lua_rawget(l, LUA_REGISTRYINDEX);
00279 if (lua_type(l, -1) != LUA_TTABLE)
00280 cout << "Metatable for " << ClassNames[id] << " not found!\n";
00281 if (lua_setmetatable(l, -2) == 0)
00282 cout << "Error setting metatable for " << ClassNames[id] << '\n';
00283 }
00284
00285
00286
00287 static void CreateClassMetatable(lua_State* l, int id)
00288 {
00289 lua_newtable(l);
00290 PushClass(l, id);
00291 lua_pushvalue(l, -2);
00292 lua_rawset(l, LUA_REGISTRYINDEX);
00293 lua_pushvalue(l, -1);
00294 PushClass(l, id);
00295 lua_rawset(l, LUA_REGISTRYINDEX);
00296
00297 lua_pushliteral(l, "__index");
00298 lua_pushvalue(l, -2);
00299 lua_rawset(l, -3);
00300 }
00301
00302
00303 static void RegisterMethod(lua_State* l, const char* name, lua_CFunction fn)
00304 {
00305 lua_pushstring(l, name);
00306 lua_pushvalue(l, -2);
00307 lua_pushcclosure(l, fn, 1);
00308 lua_settable(l, -3);
00309 }
00310
00311
00312
00313
00314 static bool istype(lua_State* l, int index, int id)
00315 {
00316
00317 if (!lua_getmetatable(l, index))
00318 return false;
00319 lua_rawget(l, LUA_REGISTRYINDEX);
00320
00321 if (lua_type(l, -1) != LUA_TSTRING)
00322 {
00323 cout << "istype failed! Unregistered class.\n";
00324 lua_pop(l, 1);
00325 return false;
00326 }
00327
00328 const char* classname = lua_tostring(l, -1);
00329 if (classname != NULL && strcmp(classname, ClassNames[id]) == 0)
00330 {
00331 lua_pop(l, 1);
00332 return true;
00333 }
00334 lua_pop(l, 1);
00335 return false;
00336 }
00337
00338
00339
00340 static void* CheckUserData(lua_State* l, int index, int id)
00341 {
00342 if (istype(l, index, id))
00343 return lua_touserdata(l, index);
00344 else
00345 return NULL;
00346 }
00347
00348
00349
00350 static CelestiaCore* getAppCore(lua_State* l, FatalErrors fatalErrors = NoErrors)
00351 {
00352 lua_pushstring(l, "celestia-appcore");
00353 lua_gettable(l, LUA_REGISTRYINDEX);
00354
00355 if (!lua_islightuserdata(l, -1))
00356 {
00357 if (fatalErrors == NoErrors)
00358 return NULL;
00359 else
00360 {
00361 lua_pushstring(l, "internal error: invalid appCore");
00362 lua_error(l);
00363 }
00364 }
00365
00366 CelestiaCore* appCore = static_cast<CelestiaCore*>(lua_touserdata(l, -1));
00367 lua_pop(l, 1);
00368 return appCore;
00369 }
00370
00371
00372 LuaState::LuaState() :
00373 timeout(MaxTimeslice),
00374 state(NULL),
00375 costate(NULL),
00376 alive(false),
00377 timer(NULL),
00378 scriptAwakenTime(0.1),
00379 ioMode(NoIO)
00380 {
00381 state = lua_open();
00382 timer = CreateTimer();
00383 screenshotCount = 0;
00384 }
00385
00386 LuaState::~LuaState()
00387 {
00388 delete timer;
00389 if (state != NULL)
00390 lua_close(state);
00391 #if 0
00392 if (costate != NULL)
00393 lua_close(costate);
00394 #endif
00395 }
00396
00397 lua_State* LuaState::getState() const
00398 {
00399 return state;
00400 }
00401
00402
00403 double LuaState::getTime() const
00404 {
00405 return timer->getTime();
00406 }
00407
00408
00409
00410
00411 static void checkTimeslice(lua_State *l, lua_Debug *ar)
00412 {
00413 lua_pushstring(l, "celestia-luastate");
00414 lua_gettable(l, LUA_REGISTRYINDEX);
00415 if (!lua_islightuserdata(l, -1))
00416 {
00417 lua_pushstring(l, "Internal Error: Invalid table entry in checkTimeslice");
00418 lua_error(l);
00419 }
00420 LuaState* luastate = static_cast<LuaState*>(lua_touserdata(l, -1));
00421 if (luastate == NULL)
00422 {
00423 lua_pushstring(l, "Internal Error: Invalid value in checkTimeslice");
00424 lua_error(l);
00425 }
00426
00427 if (luastate->timesliceExpired())
00428 {
00429 const char* errormsg = "Timeout: script hasn't returned control to celestia (forgot to call wait()?)";
00430 cerr << errormsg << "\n";
00431 lua_pushstring(l, errormsg);
00432 lua_error(l);
00433 }
00434 return;
00435 }
00436
00437
00438
00439 void LuaState::cleanup()
00440 {
00441 if (ioMode == Asking)
00442 {
00443
00444 CelestiaCore* appCore = getAppCore(costate, NoErrors);
00445 if (appCore != NULL)
00446 {
00447 lua_pushstring(state, "celestia-savedrenderflags");
00448 lua_gettable(state, LUA_REGISTRYINDEX);
00449 if (lua_isuserdata(state, -1))
00450 {
00451 int* savedrenderflags = static_cast<int*>(lua_touserdata(state, -1));
00452 appCore->getRenderer()->setRenderFlags(*savedrenderflags);
00453
00454 lua_pushstring(state, "celestia-savedrenderflags");
00455 lua_pushnil(state);
00456 lua_settable(state, LUA_REGISTRYINDEX);
00457 }
00458 lua_pop(state,1);
00459 }
00460 }
00461 lua_pushstring(costate, CleanupCallback);
00462 lua_gettable(costate, LUA_GLOBALSINDEX);
00463 if (lua_isnil(costate, -1))
00464 {
00465 return;
00466 }
00467 timeout = getTime() + 1.0;
00468 if (lua_pcall(costate, 0, 0, 0) != 0)
00469 {
00470 cerr << "Error while executing cleanup-callback: " << lua_tostring(costate, -1) << "\n";
00471 }
00472 }
00473
00474
00475 bool LuaState::createThread()
00476 {
00477
00478 if (!(lua_isfunction(state, -1) && !lua_iscfunction(state, -1)))
00479 {
00480
00481 assert(0);
00482 return false;
00483 }
00484 else
00485 {
00486 costate = lua_newthread(state);
00487 if (costate == NULL)
00488 return false;
00489 lua_sethook(costate, checkTimeslice, LUA_MASKCOUNT, 1000);
00490 lua_pushvalue(state, -2);
00491 lua_xmove(state, costate, 1);
00492 alive = true;
00493 return true;
00494 }
00495 }
00496
00497
00498 string LuaState::getErrorMessage()
00499 {
00500 if (lua_gettop(state) > 0)
00501 {
00502 if (lua_isstring(state, -1))
00503 return lua_tostring(state, -1);
00504 }
00505 return "";
00506 }
00507
00508
00509 bool LuaState::timesliceExpired()
00510 {
00511 if (timeout < getTime())
00512 {
00513
00514 lua_sethook(costate, checkTimeslice, LUA_MASKCOUNT, 1);
00515 return true;
00516 }
00517 else
00518 {
00519 return false;
00520 }
00521 }
00522
00523
00524 static int auxresume(lua_State *L, lua_State *co, int narg)
00525 {
00526 int status;
00527 #if 0
00528 if (!lua_checkstack(co, narg))
00529 luaL_error(L, "too many arguments to resume");
00530 #endif
00531 lua_xmove(L, co, narg);
00532
00533 status = lua_resume(co, narg);
00534 if (status == 0)
00535 {
00536 int nres = lua_gettop(co);
00537 #if 0
00538 if (!lua_checkstack(L, narg))
00539 luaL_error(L, "too many results to resume");
00540 #endif
00541 lua_xmove(co, L, nres);
00542 return nres;
00543 }
00544 else
00545 {
00546 lua_xmove(co, L, 1);
00547 return -1;
00548 }
00549 }
00550
00551
00552 bool LuaState::isAlive() const
00553 {
00554 return alive;
00555 }
00556
00557
00558 struct ReadChunkInfo
00559 {
00560 char* buf;
00561 int bufSize;
00562 istream* in;
00563 };
00564
00565 static const char* readStreamChunk(lua_State* state, void* udata, size_t* size)
00566 {
00567 assert(udata != NULL);
00568 if (udata == NULL)
00569 return NULL;
00570
00571 ReadChunkInfo* info = reinterpret_cast<ReadChunkInfo*>(udata);
00572 assert(info->buf != NULL);
00573 assert(info->in != NULL);
00574
00575 if (!info->in->good())
00576 {
00577 *size = 0;
00578 return NULL;
00579 }
00580
00581 info->in->read(info->buf, info->bufSize);
00582 streamsize nread = info->in->gcount();
00583
00584 *size = (size_t) nread;
00585 if (nread == 0)
00586 return NULL;
00587 else
00588 return info->buf;
00589 }
00590
00591
00592
00593
00594 bool LuaState::charEntered(const char* c_p)
00595 {
00596 if (ioMode == Asking && getTime() > timeout)
00597 {
00598 int stackTop = lua_gettop(costate);
00599 if (strcmp(c_p, "y") == 0)
00600 {
00601 lua_iolibopen(costate);
00602 ioMode = IOAllowed;
00603 }
00604 else
00605 {
00606 ioMode = IODenied;
00607 }
00608 CelestiaCore* appCore = getAppCore(costate, NoErrors);
00609 if (appCore == NULL)
00610 {
00611 cerr << "ERROR: appCore not found\n";
00612 return true;
00613 }
00614 appCore->setTextEnterMode(appCore->getTextEnterMode() & ~CelestiaCore::KbPassToScript);
00615 appCore->showText("", 0, 0, 0, 0);
00616
00617 lua_pushstring(costate, "celestia-savedrenderflags");
00618 lua_gettable(costate, LUA_REGISTRYINDEX);
00619 if (lua_isuserdata(costate, -1))
00620 {
00621 int* savedrenderflags = static_cast<int*>(lua_touserdata(costate, -1));
00622 appCore->getRenderer()->setRenderFlags(*savedrenderflags);
00623
00624 lua_pushstring(costate, "celestia-savedrenderflags");
00625 lua_pushnil(costate);
00626 lua_settable(costate, LUA_REGISTRYINDEX);
00627 }
00628 else
00629 {
00630 cerr << "Oops, expected savedrenderflags to be userdata\n";
00631 }
00632 lua_settop(costate,stackTop);
00633 return true;
00634 }
00635 int stack_top = lua_gettop(costate);
00636 bool result = true;
00637 lua_pushstring(costate, KbdCallback);
00638 lua_gettable(costate, LUA_GLOBALSINDEX);
00639 lua_pushstring(costate, c_p);
00640 timeout = getTime() + 1.0;
00641 if (lua_pcall(costate, 1, 1, 0) != 0)
00642 {
00643 cerr << "Error while executing keyboard-callback: " << lua_tostring(costate, -1) << "\n";
00644 result = false;
00645 }
00646 else
00647 {
00648 if (lua_isboolean(costate, -1))
00649 {
00650 result = static_cast<bool>(lua_toboolean(costate, -1));
00651 }
00652 }
00653
00654 lua_settop(costate, stack_top);
00655 return result;
00656 }
00657
00658
00659 int LuaState::loadScript(istream& in, const string& streamname)
00660 {
00661 char buf[4096];
00662 ReadChunkInfo info;
00663 info.buf = buf;
00664 info.bufSize = sizeof(buf);
00665 info.in = ∈
00666
00667 if (streamname != "string")
00668 {
00669 lua_pushstring(state, "celestia-scriptpath");
00670 lua_pushstring(state, streamname.c_str());
00671 lua_settable(state, LUA_REGISTRYINDEX);
00672 }
00673
00674 int status = lua_load(state, readStreamChunk, &info, streamname.c_str());
00675 if (status != 0)
00676 cout << "Error loading script: " << lua_tostring(state, -1) << '\n';
00677
00678 return status;
00679 }
00680
00681 int LuaState::loadScript(const string& s)
00682 {
00683 #ifdef HAVE_SSTREAM
00684 istringstream in(s);
00685 #else
00686 istrstream in(s.c_str());
00687 #endif
00688 return loadScript(in, "string");
00689 }
00690
00691 int LuaState::resume()
00692 {
00693 assert(costate != NULL);
00694 if (costate == NULL)
00695 return false;
00696
00697 lua_State* co = lua_tothread(state, -1);
00698
00699 if (co != costate)
00700 return false;
00701
00702 timeout = getTime() + MaxTimeslice;
00703 int nArgs = auxresume(state, co, 0);
00704 if (nArgs < 0)
00705 {
00706 alive = false;
00707
00708 const char* errorMessage = lua_tostring(state, -1);
00709
00710
00711
00712
00713
00714
00715
00716 if (strcmp(errorMessage, "cannot resume dead coroutine") != 0)
00717 {
00718 cout << "Error: " << errorMessage << '\n';
00719 CelestiaCore* appCore = getAppCore(co);
00720 if (appCore != NULL)
00721 {
00722 CelestiaCore::Alerter* alerter = appCore->getAlerter();
00723 alerter->fatalError(errorMessage);
00724 }
00725 }
00726
00727 return 1;
00728 }
00729 else
00730 {
00731 if (ioMode == Asking)
00732 {
00733
00734
00735 timeout = getTime() + 1.0;
00736 }
00737
00738 return nArgs;
00739 }
00740 }
00741
00742
00743
00744
00745 static void doError(lua_State* l, const char* errorMsg)
00746 {
00747 lua_Debug debug;
00748 if (lua_getstack(l, 1, &debug))
00749 {
00750 char buf[1024];
00751 if (lua_getinfo(l, "l", &debug))
00752 {
00753 sprintf(buf, "In line %i: %s", debug.currentline, errorMsg);
00754 lua_pushstring(l, buf);
00755 lua_error(l);
00756 }
00757 }
00758 lua_pushstring(l, errorMsg);
00759 lua_error(l);
00760 }
00761
00762
00763 bool LuaState::tick(double dt)
00764 {
00765
00766
00767
00768
00769
00770
00771
00772
00773 if (!isAlive())
00774 return false;
00775
00776 if (ioMode == Asking)
00777 {
00778 CelestiaCore* appCore = getAppCore(costate, NoErrors);
00779 if (appCore == NULL)
00780 {
00781 cerr << "ERROR: appCore not found\n";
00782 return true;
00783 }
00784 lua_pushstring(state, "celestia-savedrenderflags");
00785 lua_gettable(state, LUA_REGISTRYINDEX);
00786 if (lua_isnil(state, -1))
00787 {
00788 lua_pushstring(state, "celestia-savedrenderflags");
00789 int* savedrenderflags = static_cast<int*>(lua_newuserdata(state, sizeof(int)));
00790 *savedrenderflags = appCore->getRenderer()->getRenderFlags();
00791 lua_settable(state, LUA_REGISTRYINDEX);
00792 appCore->getRenderer()->setRenderFlags(0);
00793 }
00794
00795 lua_pop(state, 1);
00796
00797 if (getTime() > timeout)
00798 {
00799 appCore->showText("WARNING:\n\nThis script requests permission to read/write files\n"
00800 "and execute external programs. Allowing this can be\n"
00801 "dangerous.\n"
00802 "Do you trust the script and want to allow this?\n\n"
00803 "y = yes, ESC = cancel script, any other key = no",
00804 0, 0,
00805 -15, 5, 5);
00806 appCore->setTextEnterMode(appCore->getTextEnterMode() | CelestiaCore::KbPassToScript);
00807 }
00808 else
00809 {
00810 appCore->showText("WARNING:\n\nThis script requests permission to read/write files\n"
00811 "and execute external programs. Allowing this can be\n"
00812 "dangerous.\n"
00813 "Do you trust the script and want to allow this?",
00814 0, 0,
00815 -15, 5, 5);
00816 appCore->setTextEnterMode(appCore->getTextEnterMode() & ~CelestiaCore::KbPassToScript);
00817 }
00818
00819 return false;
00820 }
00821
00822 if (dt == 0 || scriptAwakenTime > getTime())
00823 return false;
00824
00825 int nArgs = resume();
00826 if (!isAlive())
00827 {
00828
00829 return true;
00830 }
00831 else
00832 {
00833
00834 lua_State* state = getState();
00835
00836
00837
00838 double delay;
00839 if (nArgs == 1 && lua_isnumber(state, -1))
00840 delay = lua_tonumber(state, -1);
00841 else
00842 delay = 0.0;
00843 scriptAwakenTime = getTime() + delay;
00844
00845
00846 lua_pop(state, nArgs);
00847 return false;
00848 }
00849 }
00850
00851
00852 void LuaState::requestIO()
00853 {
00854
00855
00856
00857
00858
00859 if (ioMode == NoIO)
00860 {
00861 CelestiaCore* appCore = getAppCore(state, AllErrors);
00862 string policy = appCore->getConfig()->scriptSystemAccessPolicy;
00863 if (policy == "allow")
00864 {
00865
00866 luaopen_io(costate);
00867 ioMode = IOAllowed;
00868 }
00869 else if (policy == "deny")
00870 {
00871 ioMode = IODenied;
00872 }
00873 else
00874 {
00875 ioMode = Asking;
00876 }
00877 }
00878 }
00879
00880
00881
00882 static void checkArgs(lua_State* l,
00883 int minArgs, int maxArgs, const char* errorMessage)
00884 {
00885 int argc = lua_gettop(l);
00886 if (argc < minArgs || argc > maxArgs)
00887 {
00888 doError(l, errorMessage);
00889 }
00890 }
00891
00892
00893 static astro::CoordinateSystem parseCoordSys(const string& name)
00894 {
00895 if (compareIgnoringCase(name, "universal") == 0)
00896 return astro::Universal;
00897 else if (compareIgnoringCase(name, "ecliptic") == 0)
00898 return astro::Ecliptical;
00899 else if (compareIgnoringCase(name, "equatorial") == 0)
00900 return astro::Equatorial;
00901 else if (compareIgnoringCase(name, "planetographic") == 0)
00902 return astro::Geographic;
00903 else if (compareIgnoringCase(name, "observer") == 0)
00904 return astro::ObserverLocal;
00905 else if (compareIgnoringCase(name, "lock") == 0)
00906 return astro::PhaseLock;
00907 else if (compareIgnoringCase(name, "chase") == 0)
00908 return astro::Chase;
00909 else
00910 return astro::Universal;
00911 }
00912
00913
00914 static Marker::Symbol parseMarkerSymbol(const string& name)
00915 {
00916 if (compareIgnoringCase(name, "diamond") == 0)
00917 return Marker::Diamond;
00918 else if (compareIgnoringCase(name, "triangle") == 0)
00919 return Marker::Triangle;
00920 else if (compareIgnoringCase(name, "square") == 0)
00921 return Marker::Square;
00922 else if (compareIgnoringCase(name, "plus") == 0)
00923 return Marker::Plus;
00924 else if (compareIgnoringCase(name, "x") == 0)
00925 return Marker::X;
00926 else
00927 return Marker::Diamond;
00928 }
00929
00930
00931
00932 LuaState* getLuaStateObject(lua_State* l)
00933 {
00934 int stackSize = lua_gettop(l);
00935 lua_pushstring(l, "celestia-luastate");
00936 lua_gettable(l, LUA_REGISTRYINDEX);
00937
00938 if (!lua_islightuserdata(l, -1))
00939 {
00940 doError(l, "Internal Error: Invalid table entry for LuaState-pointer");
00941 }
00942 LuaState* luastate_ptr = static_cast<LuaState*>(lua_touserdata(l, -1));
00943 if (luastate_ptr == NULL)
00944 {
00945 doError(l, "Internal Error: Invalid LuaState-pointer");
00946 }
00947 lua_settop(l, stackSize);
00948 return luastate_ptr;
00949 }
00950
00951
00952
00953
00954 View* getViewByObserver(CelestiaCore* appCore, Observer* obs)
00955 {
00956 for (unsigned int i = 0; i < appCore->views.size(); i++)
00957 {
00958 if ((appCore->views[i])->observer == obs)
00959 {
00960 return appCore->views[i];
00961 }
00962 }
00963 return NULL;
00964 }
00965
00966
00967 void getObservers(CelestiaCore* appCore, vector<Observer*>& list)
00968 {
00969 for (unsigned int i = 0; i < appCore->views.size(); i++)
00970 {
00971 list.push_back(appCore->views[i]->observer);
00972 }
00973 }
00974
00975
00976
00977
00978
00979 static const char* safeGetString(lua_State* l, int index, FatalErrors fatalErrors = AllErrors,
00980 const char* errorMsg = "String argument expected")
00981 {
00982 if (l == NULL)
00983 {
00984 cerr << "Error: LuaState invalid in safeGetString\n";
00985 cout << "Error: LuaState invalid in safeGetString\n";
00986 return NULL;
00987 }
00988 int argc = lua_gettop(l);
00989 if (index < 1 || index > argc)
00990 {
00991 if (fatalErrors & WrongArgc)
00992 {
00993 doError(l, errorMsg);
00994 }
00995 else
00996 return NULL;
00997 }
00998 if (!lua_isstring(l, index))
00999 {
01000 if (fatalErrors & WrongType)
01001 {
01002 doError(l, errorMsg);
01003 }
01004 else
01005 return NULL;
01006 }
01007 return lua_tostring(l, index);
01008 }
01009
01010
01011
01012 static lua_Number safeGetNumber(lua_State* l, int index, FatalErrors fatalErrors = AllErrors,
01013 const char* errorMsg = "Numeric argument expected",
01014 lua_Number defaultValue = 0.0)
01015 {
01016 if (l == NULL)
01017 {
01018 cerr << "Error: LuaState invalid in safeGetNumber\n";
01019 cout << "Error: LuaState invalid in safeGetNumber\n";
01020 return 0.0;
01021 }
01022 int argc = lua_gettop(l);
01023 if (index < 1 || index > argc)
01024 {
01025 if (fatalErrors & WrongArgc)
01026 {
01027 doError(l, errorMsg);
01028 }
01029 else
01030 return defaultValue;
01031 }
01032 if (!lua_isnumber(l, index))
01033 {
01034 if (fatalErrors & WrongType)
01035 {
01036 doError(l, errorMsg);
01037 }
01038 else
01039 return defaultValue;
01040 }
01041 return lua_tonumber(l, index);
01042 }
01043
01044
01045
01046 static void setTable(lua_State* l, const char* field, lua_Number value)
01047 {
01048 lua_pushstring(l, field);
01049 lua_pushnumber(l, value);
01050 lua_settable(l, -3);
01051 }
01052
01053 static void setTable(lua_State* l, const char* field, const char* value)
01054 {
01055 lua_pushstring(l, field);
01056 lua_pushstring(l, value);
01057 lua_settable(l, -3);
01058 }
01059
01060
01061
01062
01063 static UniversalCoord* to_position(lua_State* l, int index);
01064 static int position_new(lua_State* l, const UniversalCoord& uc);
01065
01066 static int object_new(lua_State* l, const Selection& sel);
01067
01068 static Quatd* to_rotation(lua_State* l, int index);
01069 static int rotation_new(lua_State* l, const Quatd& qd);
01070
01071
01072 static int vector_new(lua_State* l, const Vec3d& v)
01073 {
01074 Vec3d* v3 = reinterpret_cast<Vec3d*>(lua_newuserdata(l, sizeof(Vec3d)));
01075 *v3 = v;
01076 SetClass(l, _Vec3);
01077
01078 return 1;
01079 }
01080
01081 static Vec3d* to_vector(lua_State* l, int index)
01082 {
01083 return static_cast<Vec3d*>(CheckUserData(l, index, _Vec3));
01084 }
01085
01086 static Vec3d* this_vector(lua_State* l)
01087 {
01088 Vec3d* v3 = to_vector(l, 1);
01089 if (v3 == NULL)
01090 {
01091 doError(l, "Bad vector object!");
01092 }
01093
01094 return v3;
01095 }
01096
01097
01098 static int vector_sub(lua_State* l)
01099 {
01100 checkArgs(l, 2, 2, "Need two operands for sub");
01101 Vec3d* op1 = to_vector(l, 1);
01102 Vec3d* op2 = to_vector(l, 2);
01103 if (op1 == NULL || op2 == NULL)
01104 {
01105 doError(l, "Subtraction only defined for two vectors");
01106 }
01107 else
01108 {
01109 Vec3d result = *op1 - *op2;
01110 vector_new(l, result);
01111 }
01112 return 1;
01113 }
01114
01115 static int vector_get(lua_State* l)
01116 {
01117 checkArgs(l, 2, 2, "Invalid access of vector-component");
01118 Vec3d* v3 = this_vector(l);
01119 string key = safeGetString(l, 2, AllErrors, "Invalid key in vector-access");
01120 double value = 0.0;
01121 if (key == "x")
01122 value = v3->x;
01123 else if (key == "y")
01124 value = v3->y;
01125 else if (key == "z")
01126 value = v3->z;
01127 else
01128 {
01129 if (lua_getmetatable(l, 1))
01130 {
01131 lua_pushvalue(l, 2);
01132 lua_rawget(l, -2);
01133 return 1;
01134 }
01135 else
01136 {
01137 doError(l, "Internal error: couldn't get metatable");
01138 }
01139 }
01140 lua_pushnumber(l, (lua_Number)value);
01141 return 1;
01142 }
01143
01144 static int vector_set(lua_State* l)
01145 {
01146 checkArgs(l, 3, 3, "Invalid access of vector-component");
01147 Vec3d* v3 = this_vector(l);
01148 string key = safeGetString(l, 2, AllErrors, "Invalid key in vector-access");
01149 double value = safeGetNumber(l, 3, AllErrors, "Vector components must be numbers");
01150 if (key == "x")
01151 v3->x = value;
01152 else if (key == "y")
01153 v3->y = value;
01154 else if (key == "z")
01155 v3->z = value;
01156 else
01157 {
01158 doError(l, "Invalid key in vector-access");
01159 }
01160 return 0;
01161 }
01162
01163 static int vector_getx(lua_State* l)
01164 {
01165 checkArgs(l, 1, 1, "No arguments expected for vector:getx");
01166 Vec3d* v3 = this_vector(l);
01167 lua_Number x;
01168 x = static_cast<lua_Number>(v3->x);
01169 lua_pushnumber(l, x);
01170
01171 return 1;
01172 }
01173
01174 static int vector_gety(lua_State* l)
01175 {
01176 checkArgs(l, 1, 1, "No arguments expected for vector:gety");
01177 Vec3d* v3 = this_vector(l);
01178 lua_Number y;
01179 y = static_cast<lua_Number>(v3->y);
01180 lua_pushnumber(l, y);
01181
01182 return 1;
01183 }
01184
01185 static int vector_getz(lua_State* l)
01186 {
01187 checkArgs(l, 1, 1, "No arguments expected for vector:getz");
01188 Vec3d* v3 = this_vector(l);
01189 lua_Number z;
01190 z = static_cast<lua_Number>(v3->z);
01191 lua_pushnumber(l, z);
01192
01193 return 1;
01194 }
01195
01196 static int vector_normalize(lua_State* l)
01197 {
01198 checkArgs(l, 1, 1, "No arguments expected for vector:normalize");
01199 Vec3d* v = this_vector(l);
01200 Vec3d vn(*v);
01201 vn.normalize();
01202 vector_new(l, vn);
01203 return 1;
01204 }
01205
01206 static int vector_length(lua_State* l)
01207 {
01208 checkArgs(l, 1, 1, "No arguments expected for vector:length");
01209 Vec3d* v = this_vector(l);
01210 double length = v->length();
01211 lua_pushnumber(l, (lua_Number)length);
01212 return 1;
01213 }
01214
01215 static int vector_add(lua_State* l)
01216 {
01217 checkArgs(l, 2, 2, "Need two operands for addition");
01218 Vec3d* v1 = NULL;
01219 Vec3d* v2 = NULL;
01220 UniversalCoord* p = NULL;
01221
01222 if (istype(l, 1, _Vec3) && istype(l, 2, _Vec3))
01223 {
01224 v1 = to_vector(l, 1);
01225 v2 = to_vector(l, 2);
01226 vector_new(l, *v1 + *v2);
01227 }
01228 else
01229 if (istype(l, 1, _Vec3) && istype(l, 2, _Position))
01230 {
01231 v1 = to_vector(l, 1);
01232 p = to_position(l, 2);
01233 position_new(l, *p + *v1);
01234 }
01235 else
01236 {
01237 doError(l, "Bad vector addition!");
01238 }
01239 return 1;
01240 }
01241
01242 static int vector_mult(lua_State* l)
01243 {
01244 checkArgs(l, 2, 2, "Need two operands for multiplication");
01245 Vec3d* v1 = NULL;
01246 Vec3d* v2 = NULL;
01247 Quatd* q = NULL;
01248 lua_Number s = 0.0;
01249 if (istype(l, 1, _Vec3) && istype(l, 2, _Vec3))
01250 {
01251 v1 = to_vector(l, 1);
01252 v2 = to_vector(l, 2);
01253 lua_pushnumber(l, *v1 * *v2);
01254 }
01255 else
01256 if (istype(l, 1, _Vec3) && lua_isnumber(l, 2))
01257 {
01258 v1 = to_vector(l, 1);
01259 s = lua_tonumber(l, 2);
01260 vector_new(l, *v1 * s);
01261 }
01262 else
01263 if (istype(l, 1, _Vec3) && istype(l, 2, _Rotation))
01264 {
01265 v1 = to_vector(l, 1);
01266 q = to_rotation(l, 2);
01267 rotation_new(l, *v1 * *q);
01268 }
01269 else
01270 if (lua_isnumber(l, 1) && istype(l, 2, _Vec3))
01271 {
01272 s = lua_tonumber(l, 1);
01273 v1 = to_vector(l, 2);
01274 vector_new(l, *v1 * s);
01275 }
01276 else
01277 {
01278 doError(l, "Bad vector multiplication!");
01279 }
01280 return 1;
01281 }
01282
01283 static int vector_cross(lua_State* l)
01284 {
01285 checkArgs(l, 2, 2, "Need two operands for multiplication");
01286 Vec3d* v1 = NULL;
01287 Vec3d* v2 = NULL;
01288 if (istype(l, 1, _Vec3) && istype(l, 2, _Vec3))
01289 {
01290 v1 = to_vector(l, 1);
01291 v2 = to_vector(l, 2);
01292 vector_new(l, *v1 ^ *v2);
01293 }
01294 else
01295 {
01296 doError(l, "Bad vector multiplication!");
01297 }
01298 return 1;
01299
01300 }
01301
01302 static int vector_tostring(lua_State* l)
01303 {
01304 lua_pushstring(l, "[Vector]");
01305 return 1;
01306 }
01307
01308 static void CreateVectorMetaTable(lua_State* l)
01309 {
01310 CreateClassMetatable(l, _Vec3);
01311
01312 RegisterMethod(l, "__tostring", vector_tostring);
01313 RegisterMethod(l, "__add", vector_add);
01314 RegisterMethod(l, "__sub", vector_sub);
01315 RegisterMethod(l, "__mul", vector_mult);
01316 RegisterMethod(l, "__pow", vector_cross);
01317 RegisterMethod(l, "__index", vector_get);
01318 RegisterMethod(l, "__newindex", vector_set);
01319 RegisterMethod(l, "getx", vector_getx);
01320 RegisterMethod(l, "gety", vector_gety);
01321 RegisterMethod(l, "getz", vector_getz);
01322 RegisterMethod(l, "normalize", vector_normalize);
01323 RegisterMethod(l, "length", vector_length);
01324
01325 lua_pop(l, 1);
01326 }
01327
01328
01329 static int rotation_new(lua_State* l, const Quatd& qd)
01330 {
01331 Quatd* q = reinterpret_cast<Quatd*>(lua_newuserdata(l, sizeof(Quatd)));
01332 *q = qd;
01333 SetClass(l, _Rotation);
01334
01335 return 1;
01336 }
01337
01338 static Quatd* to_rotation(lua_State* l, int index)
01339 {
01340 return static_cast<Quatd*>(CheckUserData(l, index, _Rotation));
01341 }
01342
01343 static Quatd* this_rotation(lua_State* l)
01344 {
01345 Quatd* q = to_rotation(l, 1);
01346 if (q == NULL)
01347 {
01348 doError(l, "Bad rotation object!");
01349 }
01350
01351 return q;
01352 }
01353
01354
01355 static int rotation_add(lua_State* l)
01356 {
01357 checkArgs(l, 2, 2, "Need two operands for add");
01358 Quatd* q1 = to_rotation(l, 1);
01359 Quatd* q2 = to_rotation(l, 2);
01360 if (q1 == NULL || q2 == NULL)
01361 {
01362 doError(l, "Addition only defined for two rotations");
01363 }
01364 else
01365 {
01366 Quatd result = *q1 + *q2;
01367 rotation_new(l, result);
01368 }
01369 return 1;
01370 }
01371
01372 static int rotation_mult(lua_State* l)
01373 {
01374 checkArgs(l, 2, 2, "Need two operands for multiplication");
01375 Quatd* r1 = NULL;
01376 Quatd* r2 = NULL;
01377 Vec3d* v = NULL;
01378 lua_Number s = 0.0;
01379 if (istype(l, 1, _Rotation) && istype(l, 2, _Rotation))
01380 {
01381 r1 = to_rotation(l, 1);
01382 r2 = to_rotation(l, 2);
01383 rotation_new(l, *r1 * *r2);
01384 }
01385 else
01386 if (istype(l, 1, _Rotation) && lua_isnumber(l, 2))
01387 {
01388 r1 = to_rotation(l, 1);
01389 s = lua_tonumber(l, 2);
01390 rotation_new(l, *r1 * s);
01391 }
01392 else
01393 if (lua_isnumber(l, 1) && istype(l, 2, _Rotation))
01394 {
01395 s = lua_tonumber(l, 1);
01396 r1 = to_rotation(l, 2);
01397 rotation_new(l, *r1 * s);
01398 }
01399 else
01400 {
01401 doError(l, "Bad rotation multiplication!");
01402 }
01403 return 1;
01404 }
01405
01406 static int rotation_imag(lua_State* l)
01407 {
01408 checkArgs(l, 1, 1, "No arguments expected for rotation_imag");
01409 Quatd* q = this_rotation(l);
01410 vector_new(l, imag(*q));
01411 return 1;
01412 }
01413
01414 static int rotation_real(lua_State* l)
01415 {
01416 checkArgs(l, 1, 1, "No arguments expected for rotation_real");
01417 Quatd* q = this_rotation(l);
01418 lua_pushnumber(l, real(*q));
01419 return 1;
01420 }
01421
01422 static int rotation_transform(lua_State* l)
01423 {
01424 checkArgs(l, 2, 2, "One argument expected for rotation:transform()");
01425 Quatd* q = this_rotation(l);
01426 Vec3d* v = to_vector(l, 2);
01427 if (v == NULL)
01428 {
01429 doError(l, "Argument to rotation:transform() must be a vector");
01430 }
01431 vector_new(l, *v * q->toMatrix3());
01432 return 1;
01433 }
01434
01435 static int rotation_setaxisangle(lua_State* l)
01436 {
01437 checkArgs(l, 3, 3, "Two arguments expected for rotation:setaxisangle()");
01438 Quatd* q = this_rotation(l);
01439 Vec3d* v = to_vector(l, 2);
01440 if (v == NULL)
01441 {
01442 doError(l, "setaxisangle: first argument must be a vector");
01443 }
01444 double angle = safeGetNumber(l, 3, AllErrors, "second argument to rotation:setaxisangle must be a number");
01445 q->setAxisAngle(*v, angle);
01446 return 0;
01447 }
01448
01449 static int rotation_slerp(lua_State* l)
01450 {
01451 checkArgs(l, 3, 3, "Two arguments expected for rotation:slerp()");
01452 Quatd* q1 = this_rotation(l);
01453 Quatd* q2 = to_rotation(l, 2);
01454 if (q2 == NULL)
01455 {
01456 doError(l, "slerp: first argument must be a rotation");
01457 }
01458 double t = safeGetNumber(l, 3, AllErrors, "second argument to rotation:slerp must be a number");
01459 rotation_new(l, Quatd::slerp(*q1, *q2, t));
01460 return 1;
01461 }
01462
01463 static int rotation_get(lua_State* l)
01464 {
01465 checkArgs(l, 2, 2, "Invalid access of rotation-component");
01466 Quatd* q3 = this_rotation(l);
01467 string key = safeGetString(l, 2, AllErrors, "Invalid key in rotation-access");
01468 double value = 0.0;
01469 if (key == "x")
01470 value = imag(*q3).x;
01471 else if (key == "y")
01472 value = imag(*q3).y;
01473 else if (key == "z")
01474 value = imag(*q3).z;
01475 else if (key == "w")
01476 value = real(*q3);
01477 else
01478 {
01479 if (lua_getmetatable(l, 1))
01480 {
01481 lua_pushvalue(l, 2);
01482 lua_rawget(l, -2);
01483 return 1;
01484 }
01485 else
01486 {
01487 doError(l, "Internal error: couldn't get metatable");
01488 }
01489 }
01490 lua_pushnumber(l, (lua_Number)value);
01491 return 1;
01492 }
01493
01494 static int rotation_set(lua_State* l)
01495 {
01496 checkArgs(l, 3, 3, "Invalid access of rotation-component");
01497 Quatd* q3 = this_rotation(l);
01498 string key = safeGetString(l, 2, AllErrors, "Invalid key in rotation-access");
01499 double value = safeGetNumber(l, 3, AllErrors, "Rotation components must be numbers");
01500 Vec3d v = imag(*q3);
01501 double w = real(*q3);
01502 if (key == "x")
01503 v.x = value;
01504 else if (key == "y")
01505 v.y = value;
01506 else if (key == "z")
01507 v.z = value;
01508 else if (key == "w")
01509 w = value;
01510 else
01511 {
01512 doError(l, "Invalid key in rotation-access");
01513 }
01514 *q3 = Quatd(w, v);
01515 return 0;
01516 }
01517
01518 static int rotation_tostring(lua_State* l)
01519 {
01520 lua_pushstring(l, "[Rotation]");
01521 return 1;
01522 }
01523
01524 static void CreateRotationMetaTable(lua_State* l)
01525 {
01526 CreateClassMetatable(l, _Rotation);
01527
01528 RegisterMethod(l, "real", rotation_real);
01529 RegisterMethod(l, "imag", rotation_imag);
01530 RegisterMethod(l, "transform", rotation_transform);
01531 RegisterMethod(l, "setaxisangle", rotation_setaxisangle);
01532 RegisterMethod(l, "slerp", rotation_slerp);
01533 RegisterMethod(l, "__tostring", rotation_tostring);
01534 RegisterMethod(l, "__add", rotation_add);
01535 RegisterMethod(l, "__mul", rotation_mult);
01536 RegisterMethod(l, "__index", rotation_get);
01537 RegisterMethod(l, "__newindex", rotation_set);
01538
01539 lua_pop(l, 1);
01540 }
01541
01542
01543
01544 static int position_new(lua_State* l, const UniversalCoord& uc)
01545 {
01546 UniversalCoord* ud = reinterpret_cast<UniversalCoord*>(lua_newuserdata(l, sizeof(UniversalCoord)));
01547 *ud = uc;
01548
01549 SetClass(l, _Position);
01550
01551 return 1;
01552 }
01553
01554 static UniversalCoord* to_position(lua_State* l, int index)
01555 {
01556 return static_cast<UniversalCoord*>(CheckUserData(l, index, _Position));
01557 }
01558
01559 static UniversalCoord* this_position(lua_State* l)
01560 {
01561 UniversalCoord* uc = to_position(l, 1);
01562 if (uc == NULL)
01563 {
01564 doError(l, "Bad position object!");
01565 }
01566
01567 return uc;
01568 }
01569
01570
01571 static int position_get(lua_State* l)
01572 {
01573 checkArgs(l, 2, 2, "Invalid access of position-component");
01574 UniversalCoord* uc = this_position(l);
01575 string key = safeGetString(l, 2, AllErrors, "Invalid key in position-access");
01576 double value = 0.0;
01577 if (key == "x")
01578 value = uc->x;
01579 else if (key == "y")
01580 value = uc->y;
01581 else if (key == "z")
01582 value = uc->z;
01583 else
01584 {
01585 if (lua_getmetatable(l, 1))
01586 {
01587 lua_pushvalue(l, 2);
01588 lua_rawget(l, -2);
01589 return 1;
01590 }
01591 else
01592 {
01593 doError(l, "Internal error: couldn't get metatable");
01594 }
01595 }
01596 lua_pushnumber(l, (lua_Number)value);
01597 return 1;
01598 }
01599
01600 static int position_set(lua_State* l)
01601 {
01602 checkArgs(l, 3, 3, "Invalid access of position-component");
01603 UniversalCoord* uc = this_position(l);
01604 string key = safeGetString(l, 2, AllErrors, "Invalid key in position-access");
01605 double value = safeGetNumber(l, 3, AllErrors, "Position components must be numbers");
01606 if (key == "x")
01607 uc->x = value;
01608 else if (key == "y")
01609 uc->y = value;
01610 else if (key == "z")
01611 uc->z = value;
01612 else
01613 {
01614 doError(l, "Invalid key in position-access");
01615 }
01616 return 0;
01617 }
01618
01619 static int position_getx(lua_State* l)
01620 {
01621 checkArgs(l, 1, 1, "No arguments expected for position:getx()");
01622
01623 UniversalCoord* uc = this_position(l);
01624 lua_Number x;
01625 x = uc->x;
01626 lua_pushnumber(l, x);
01627
01628 return 1;
01629 }
01630
01631 static int position_gety(lua_State* l)
01632 {
01633 checkArgs(l, 1, 1, "No arguments expected for position:gety()");
01634
01635 UniversalCoord* uc = this_position(l);
01636 lua_Number y;
01637 y = uc->y;
01638 lua_pushnumber(l, y);
01639
01640 return 1;
01641 }
01642
01643 static int position_getz(lua_State* l)
01644 {
01645 checkArgs(l, 1, 1, "No arguments expected for position:getz()");
01646
01647 UniversalCoord* uc = this_position(l);
01648 lua_Number z;
01649 z = uc->z;
01650 lua_pushnumber(l, z);
01651
01652 return 1;
01653 }
01654
01655 static int position_vectorto(lua_State* l)
01656 {
01657 checkArgs(l, 2, 2, "One argument expected to position:vectorto");
01658
01659 UniversalCoord* uc = this_position(l);
01660 UniversalCoord* uc2 = to_position(l, 2);
01661
01662 if (uc2 == NULL)
01663 {
01664 doError(l, "Argument to position:vectorto must be a position");
01665 }
01666 Vec3d diff = *uc2 - *uc;
01667 vector_new(l, diff);
01668 return 1;
01669 }
01670
01671 static int position_orientationto(lua_State* l)
01672 {
01673 checkArgs(l, 3, 3, "Two arguments expected for position:orientationto");
01674
01675 UniversalCoord* src = this_position(l);
01676 UniversalCoord* target = to_position(l, 2);
01677
01678 if (target == NULL)
01679 {
01680 doError(l, "First argument to position:orientationto must be a position");
01681 }
01682
01683 Vec3d* upd = to_vector(l, 3);
01684 if (upd == NULL)
01685 {
01686 doError(l, "Second argument to position:orientationto must be a vector");
01687 }
01688
01689 Vec3d src2target = *target - *src;
01690 src2target.normalize();
01691 Vec3d v = src2target ^ *upd;
01692 v.normalize();
01693 Vec3d u = v ^ src2target;
01694 Quatd qd = Quatd(Mat3d(v, u, -src2target));
01695 rotation_new(l, qd);
01696
01697 return 1;
01698 }
01699
01700 static int position_tostring(lua_State* l)
01701 {
01702
01703 lua_pushstring(l, "[Position]");
01704
01705 return 1;
01706 }
01707
01708 static int position_distanceto(lua_State* l)
01709 {
01710 checkArgs(l, 2, 2, "One argument expected to position:distanceto()");
01711
01712 UniversalCoord* uc = this_position(l);
01713 UniversalCoord* uc2 = to_position(l, 2);
01714 if (uc2 == NULL)
01715 {
01716 doError(l, "Position expected as argument to position:distanceto");
01717 }
01718
01719 Vec3d v = *uc2 - *uc;
01720 lua_pushnumber(l, astro::microLightYearsToKilometers(v.length()));
01721
01722 return 1;
01723 }
01724
01725 static int position_add(lua_State* l)
01726 {
01727 checkArgs(l, 2, 2, "Need two operands for addition");
01728 UniversalCoord* p1 = NULL;
01729 UniversalCoord* p2 = NULL;
01730 Vec3d* v2 = NULL;
01731
01732 if (istype(l, 1, _Position) && istype(l, 2, _Position))
01733 {
01734 p1 = to_position(l, 1);
01735 p2 = to_position(l, 2);
01736
01737 position_new(l, *p1 + *p2);
01738 }
01739 else
01740 if (istype(l, 1, _Position) && istype(l, 2, _Vec3))
01741 {
01742 p1 = to_position(l, 1);
01743 v2 = to_vector(l, 2);
01744 position_new(l, *p1 + *v2);
01745 }
01746 else
01747 {
01748 doError(l, "Bad position addition!");
01749 }
01750 return 1;
01751 }
01752
01753 static int position_sub(lua_State* l)
01754 {
01755 checkArgs(l, 2, 2, "Need two operands for subtraction");
01756 UniversalCoord* p1 = NULL;
01757 UniversalCoord* p2 = NULL;
01758 Vec3d* v2 = NULL;
01759
01760 if (istype(l, 1, _Position) && istype(l, 2, _Position))
01761 {
01762 p1 = to_position(l, 1);
01763 p2 = to_position(l, 2);
01764 vector_new(l, *p1 - *p2);
01765 }
01766 else
01767 if (istype(l, 1, _Position) && istype(l, 2, _Vec3))
01768 {
01769 p1 = to_position(l, 1);
01770 v2 = to_vector(l, 2);
01771 position_new(l, *p1 - *v2);
01772 }
01773 else
01774 {
01775 doError(l, "Bad position subtraction!");
01776 }
01777 return 1;
01778 }
01779
01780 static int position_addvector(lua_State* l)
01781 {
01782 checkArgs(l, 2, 2, "One argument expected to position:addvector()");
01783 UniversalCoord* uc = this_position(l);
01784 Vec3d* v3d = to_vector(l, 2);
01785 if (v3d == NULL)
01786 {
01787 doError(l, "Vector expected as argument to position:addvector");
01788 }
01789 else
01790 if (uc != NULL && v3d != NULL)
01791 {
01792 UniversalCoord ucnew = *uc + *v3d;
01793 position_new(l, ucnew);
01794 }
01795 return 1;
01796 }
01797
01798 static void CreatePositionMetaTable(lua_State* l)
01799 {
01800 CreateClassMetatable(l, _Position);
01801
01802 RegisterMethod(l, "__tostring", position_tostring);
01803 RegisterMethod(l, "distanceto", position_distanceto);
01804 RegisterMethod(l, "vectorto", position_vectorto);
01805 RegisterMethod(l, "orientationto", position_orientationto);
01806 RegisterMethod(l, "addvector", position_addvector);
01807 RegisterMethod(l, "__add", position_add);
01808 RegisterMethod(l, "__sub", position_sub);
01809 RegisterMethod(l, "__index", position_get);
01810 RegisterMethod(l, "__newindex", position_set);
01811 RegisterMethod(l, "getx", position_getx);
01812 RegisterMethod(l, "gety", position_gety);
01813 RegisterMethod(l, "getz", position_getz);
01814
01815 lua_pop(l, 1);
01816 }
01817
01818
01819 static int frame_new(lua_State* l, const FrameOfReference& f)
01820 {
01821 FrameOfReference* ud = reinterpret_cast<FrameOfReference*>(lua_newuserdata(l, sizeof(FrameOfReference)));
01822 *ud = f;
01823
01824 SetClass(l, _Frame);
01825
01826 return 1;
01827 }
01828
01829 static FrameOfReference* to_frame(lua_State* l, int index)
01830 {
01831 return static_cast<FrameOfReference*>(CheckUserData(l, index, _Frame));
01832 }
01833
01834 static FrameOfReference* this_frame(lua_State* l)
01835 {
01836 FrameOfReference* f = to_frame(l, 1);
01837 if (f == NULL)
01838 {
01839 doError(l, "Bad frame object!");
01840 }
01841
01842 return f;
01843 }
01844
01845
01846
01847 static int frame_from(lua_State* l)
01848 {
01849 checkArgs(l, 2, 3, "Two or three arguments required for frame:from");
01850
01851 FrameOfReference* frame = this_frame(l);
01852 CelestiaCore* appCore = getAppCore(l, AllErrors);
01853
01854 RigidTransform rt;
01855
01856 UniversalCoord* uc = NULL;
01857 Quatd* q = NULL;
01858 double jd = 0.0;
01859
01860 if (istype(l, 2, _Position))
01861 {
01862 uc = to_position(l, 2);
01863 }
01864 else if (istype(l, 2, _Rotation))
01865 {
01866 q = to_rotation(l, 2);
01867 }
01868 if (uc == NULL && q == NULL)
01869 {
01870 doError(l, "Position or rotation expected as second argument to frame:from()");
01871 }
01872
01873 jd = safeGetNumber(l, 3, WrongType, "Second arg to frame:from must be a number", appCore->getSimulation()->getTime());
01874
01875 if (uc != NULL)
01876 {
01877 rt.translation = *uc;
01878 rt = frame->toUniversal(rt, jd);
01879 position_new(l, rt.translation);
01880 }
01881 else
01882 {
01883 rt.rotation = *q;
01884 rt = frame->toUniversal(rt, jd);
01885 rotation_new(l, rt.rotation);
01886 }
01887
01888 return 1;
01889 }
01890
01891
01892 static int frame_to(lua_State* l)
01893 {
01894 checkArgs(l, 2, 3, "Two or three arguments required for frame:to");
01895
01896 FrameOfReference* frame = this_frame(l);
01897 CelestiaCore* appCore = getAppCore(l, AllErrors);
01898
01899 RigidTransform rt;
01900
01901 UniversalCoord* uc = NULL;
01902 Quatd* q = NULL;
01903 double jd = 0.0;
01904
01905 if (istype(l, 2, _Position))
01906 {
01907 uc = to_position(l, 2);
01908 }
01909 else
01910 if (istype(l, 2, _Rotation))
01911 {
01912 q = to_rotation(l, 2);
01913 }
01914
01915 if (uc == NULL && q == NULL)
01916 {
01917 doError(l, "Position or rotation expected as second argument to frame:to()");
01918 }
01919
01920 jd = safeGetNumber(l, 3, WrongType, "Second arg to frame:to must be a number", appCore->getSimulation()->getTime());
01921
01922 if (uc != NULL)
01923 {
01924 rt.translation = *uc;
01925 rt = frame->fromUniversal(rt, jd);
01926 position_new(l, rt.translation);
01927 }
01928 else
01929 {
01930 rt.rotation = *q;
01931 rt = frame->fromUniversal(rt, jd);
01932 rotation_new(l, rt.rotation);
01933 }
01934
01935 return 1;
01936 }
01937
01938 static int frame_getrefobject(lua_State* l)
01939 {
01940 checkArgs(l, 1, 1, "No arguments expected for frame:getrefobject()");
01941
01942 FrameOfReference* frame = this_frame(l);
01943 if (frame->refObject.getType() == Selection::Type_Nil)
01944 {
01945 lua_pushnil(l);
01946 }
01947 else
01948 {
01949 object_new(l, frame->refObject);
01950 }
01951 return 1;
01952 }
01953
01954 static int frame_gettargetobject(lua_State* l)
01955 {
01956 checkArgs(l, 1, 1, "No arguments expected for frame:gettarget()");
01957
01958 FrameOfReference* frame = this_frame(l);
01959 if (frame->targetObject.getType() == Selection::Type_Nil)
01960 {
01961 lua_pushnil(l);
01962 }
01963 else
01964 {
01965 object_new(l, frame->targetObject);
01966 }
01967 return 1;
01968 }
01969
01970 static int frame_getcoordinatesystem(lua_State* l)
01971 {
01972 checkArgs(l, 1, 1, "No arguments expected for frame:getcoordinatesystem()");
01973
01974 FrameOfReference* frame = this_frame(l);
01975 string coordsys;
01976 switch (frame->coordSys)
01977 {
01978 case astro::Universal:
01979 coordsys = "universal"; break;
01980 case astro::Ecliptical:
01981 coordsys = "ecliptic"; break;
01982 case astro::Equatorial:
01983 coordsys = "equatorial"; break;
01984 case astro::Geographic:
01985 coordsys = "planetographic"; break;
01986 case astro::ObserverLocal:
01987 coordsys = "observer"; break;
01988 case astro::PhaseLock:
01989 coordsys = "lock"; break;
01990 case astro::Chase:
01991 coordsys = "chase"; break;
01992 default:
01993 coordsys = "invalid";
01994 }
01995 lua_pushstring(l, coordsys.c_str());
01996 return 1;
01997 }
01998
01999 static int frame_tostring(lua_State* l)
02000 {
02001
02002 lua_pushstring(l, "[Frame]");
02003
02004 return 1;
02005 }
02006
02007 static void CreateFrameMetaTable(lua_State* l)
02008 {
02009 CreateClassMetatable(l, _Frame);
02010
02011 RegisterMethod(l, "__tostring", frame_tostring);
02012 RegisterMethod(l, "to", frame_to);
02013 RegisterMethod(l, "from", frame_from);
02014 RegisterMethod(l, "getcoordinatesystem", frame_getcoordinatesystem);
02015 RegisterMethod(l, "getrefobject", frame_getrefobject);
02016 RegisterMethod(l, "gettargetobject", frame_gettargetobject);
02017
02018 lua_pop(l, 1);
02019 }
02020
02021
02022
02023 static int object_new(lua_State* l, const Selection& sel)
02024 {
02025 Selection* ud = reinterpret_cast<Selection*>(lua_newuserdata(l, sizeof(Selection)));
02026 *ud = sel;
02027
02028 SetClass(l, _Object);
02029
02030 return 1;
02031 }
02032
02033 static Selection* to_object(lua_State* l, int index)
02034 {
02035 return static_cast<Selection*>(CheckUserData(l, index, _Object));
02036 }
02037
02038 static Selection* this_object(lua_State* l)
02039 {
02040 Selection* sel = to_object(l, 1);
02041 if (sel == NULL)
02042 {
02043 doError(l, "Bad position object!");
02044 }
02045
02046 return sel;
02047 }
02048
02049
02050 static int object_tostring(lua_State* l)
02051 {
02052 lua_pushstring(l, "[Object]");
02053
02054 return 1;
02055 }
02056
02057 static int object_radius(lua_State* l)
02058 {
02059 checkArgs(l, 1, 1, "No arguments expected to function object:radius");
02060
02061 Selection* sel = this_object(l);
02062 lua_pushnumber(l, sel->radius());
02063
02064 return 1;
02065 }
02066
02067 static int object_type(lua_State* l)
02068 {
02069 checkArgs(l, 1, 1, "No arguments expected to function object:type");
02070
02071 Selection* sel = this_object(l);
02072 const char* tname = "unknown";
02073 switch (sel->getType())
02074 {
02075 case Selection::Type_Body:
02076 {
02077 int cl = sel->body()->getClassification();
02078 switch (cl)
02079 {
02080 case Body::Planet : tname = "planet"; break;
02081 case Body::Moon : tname = "moon"; break;
02082 case Body::Asteroid : tname = "asteroid"; break;
02083 case Body::Comet : tname = "comet"; break;
02084 case Body::Spacecraft : tname = "spacecraft"; break;
02085 case Body::Invisible : tname = "invisible"; break;
02086 }
02087 }
02088 break;
02089
02090 case Selection::Type_Star:
02091 tname = "star";
02092 break;
02093
02094 case Selection::Type_DeepSky:
02095
02096 tname = "deepsky";
02097 break;
02098
02099 case Selection::Type_Location:
02100 tname = "location";
02101 break;
02102
02103 case Selection::Type_Nil:
02104 tname = "null";
02105 break;
02106 }
02107
02108 lua_pushstring(l, tname);
02109
02110 return 1;
02111 }
02112
02113 static int object_name(lua_State* l)
02114 {
02115 checkArgs(l, 1, 1, "No arguments expected to function object:name");
02116
02117 Selection* sel = this_object(l);
02118 switch (sel->getType())
02119 {
02120 case Selection::Type_Body:
02121 lua_pushstring(l, sel->body()->getName().c_str());
02122 break;
02123 case Selection::Type_DeepSky:
02124 lua_pushstring(l, getAppCore(l, AllErrors)->getSimulation()->getUniverse()
02125 ->getDSOCatalog()->getDSOName(sel->deepsky()).c_str());
02126 break;
02127 case Selection::Type_Star:
02128 lua_pushstring(l, getAppCore(l, AllErrors)->getSimulation()->getUniverse()
02129 ->getStarCatalog()->getStarName(*(sel->star())).c_str());
02130 break;
02131 case Selection::Type_Location:
02132 lua_pushstring(l, sel->location()->getName().c_str());
02133 break;
02134 default:
02135 lua_pushstring(l, "?");
02136 break;
02137 }
02138
02139 return 1;
02140 }
02141
02142 static int object_spectraltype(lua_State* l)
02143 {
02144 checkArgs(l, 1, 1, "No arguments expected to function object:spectraltype");
02145
02146 Selection* sel = this_object(l);
02147 if (sel->star() != NULL)
02148 {
02149 char buf[16];
02150 strncpy(buf, sel->star()->getSpectralType(), sizeof buf);
02151 buf[sizeof(buf) - 1] = '\0';
02152 lua_pushstring(l, buf);
02153 }
02154 else
02155 {
02156 lua_pushnil(l);
02157 }
02158
02159 return 1;
02160 }
02161
02162 static int object_getinfo(lua_State* l)
02163 {
02164 checkArgs(l, 1, 1, "No arguments expected to function object:getinfo");
02165
02166 lua_newtable(l);
02167
02168 Selection* sel = this_object(l);
02169 if (sel->star() != NULL)
02170 {
02171 Star* star = sel->star();
02172 setTable(l, "type", "star");
02173 setTable(l, "name", getAppCore(l, AllErrors)->getSimulation()->getUniverse()
02174 ->getStarCatalog()->getStarName(*(sel->star())).c_str());
02175 setTable(l, "catalogNumber", star->getCatalogNumber());
02176 setTable(l, "stellarClass", star->getSpectralType());
02177 setTable(l, "absoluteMagnitude", (lua_Number)star->getAbsoluteMagnitude());
02178 setTable(l, "luminosity", (lua_Number)star->getLuminosity());
02179 setTable(l, "radius", (lua_Number)star->getRadius());
02180 setTable(l, "temperature", (lua_Number)star->getTemperature());
02181 setTable(l, "rotationPeriod", (lua_Number)star->getRotationElements().period);
02182 setTable(l, "bolometricMagnitude", (lua_Number)star->getBolometricMagnitude());
02183
02184 if (star->getOrbitBarycenter() != NULL)
02185 {
02186 Selection parent((Star*)(star->getOrbitBarycenter()));
02187 lua_pushstring(l, "parent");
02188 object_new(l, parent);
02189 lua_settable(l, -3);
02190 }
02191 }
02192 else if (sel->body() != NULL)
02193 {
02194 Body* body = sel->body();
02195 const char* tname = "unknown";
02196 switch (body->getClassification())
02197 {
02198 case Body::Planet : tname = "planet"; break;
02199 case Body::Moon : tname = "moon"; break;
02200 case Body::Asteroid : tname = "asteroid"; break;
02201 case Body::Comet : tname = "comet"; break;
02202 case Body::Spacecraft : tname = "spacecraft"; break;
02203 case Body::Invisible : tname = "invisible"; break;
02204 }
02205 setTable(l, "type", tname);
02206 setTable(l, "name", body->getName().c_str());
02207 setTable(l, "mass", (lua_Number)body->getMass());
02208 setTable(l, "oblateness", (lua_Number)body->getOblateness());
02209 setTable(l, "albedo", (lua_Number)body->getAlbedo());
02210 setTable(l, "infoURL", body->getInfoURL().c_str());
02211 setTable(l, "radius", (lua_Number)body->getRadius());
02212
02213 double lifespanStart, lifespanEnd;
02214 body->getLifespan(lifespanStart, lifespanEnd);
02215 setTable(l, "lifespanStart", (lua_Number)lifespanStart);
02216 setTable(l, "lifespanEnd", (lua_Number)lifespanEnd);
02217
02218
02219 PlanetarySystem* system = body->getSystem();
02220 if (system->getPrimaryBody() != NULL)
02221 {
02222 Selection parent(system->getPrimaryBody());
02223 lua_pushstring(l, "parent");
02224 object_new(l, parent);
02225 lua_settable(l, -3);
02226 }
02227 else
02228 {
02229 Selection parent(system->getStar());
02230 lua_pushstring(l, "parent");
02231 object_new(l, parent);
02232 lua_settable(l, -3);
02233 }
02234
02235 lua_pushstring(l, "hasRings");
02236 lua_pushboolean(l, body->getRings() != NULL);
02237 lua_settable(l, -3);
02238 RotationElements re = body->getRotationElements();
02239 setTable(l, "rotationPeriod", (double)re.period);
02240 setTable(l, "rotationOffset", (double)re.offset);
02241 setTable(l, "rotationEpoch", re.epoch);
02242 setTable(l, "rotationObliquity", (double)re.obliquity);
02243 setTable(l, "rotationAscendingNode", (double)re.ascendingNode);
02244 setTable(l, "rotationPrecessionRate", (double)re.precessionRate);
02245 Orbit* orbit = body->getOrbit();
02246 setTable(l, "orbitPeriod", orbit->getPeriod());
02247 Atmosphere* atmosphere = body->getAtmosphere();
02248 if (atmosphere != NULL)
02249 {
02250 setTable(l, "atmosphereHeight", (double)atmosphere->height);
02251 setTable(l, "atmosphereCloudHeight", (double)atmosphere->cloudHeight);
02252 setTable(l, "atmosphereCloudSpeed", (double)atmosphere->cloudSpeed);
02253 }
02254 }
02255 else if (sel->deepsky() != NULL)
02256 {
02257 setTable(l, "type", "deepsky");
02258 DeepSkyObject* deepsky = sel->deepsky();
02259 setTable(l, "name", getAppCore(l, AllErrors)->getSimulation()->getUniverse()
02260 ->getDSOCatalog()->getDSOName(sel->deepsky()).c_str());
02261 setTable(l, "radius", (lua_Number)deepsky->getRadius());
02262 }
02263 else if (sel->location() != NULL)
02264 {
02265 setTable(l, "type", "location");
02266 Location* location = sel->location();
02267 setTable(l, "name", location->getName().c_str());
02268 setTable(l, "size", (lua_Number)location->getSize());
02269 setTable(l, "importance", (lua_Number)location->getImportance());
02270 setTable(l, "infoURL", location->getInfoURL().c_str());
02271
02272 uint32 featureType = location->getFeatureType();
02273 string featureName("Unknown");
02274 for (FlagMap::const_iterator it = LocationFlagMap.begin(); it != LocationFlagMap.end(); it++)
02275 {
02276 if (it->second == featureType)
02277 {
02278 featureName = it->first;
02279 break;
02280 }
02281 }
02282 setTable(l, "featureType", featureName.c_str());
02283
02284 Body* parent = location->getParentBody();
02285 if (parent != NULL)
02286 {
02287 Selection selection(parent);
02288 lua_pushstring(l, "parent");
02289 object_new(l, selection);
02290 lua_settable(l, -3);
02291 }
02292 }
02293 else
02294 {
02295 setTable(l, "type", "null");
02296 }
02297 return 1;
02298 }
02299
02300 static int object_absmag(lua_State* l)
02301 {
02302 checkArgs(l, 1, 1, "No arguments expected to function object:absmag");
02303
02304 Selection* sel = this_object(l);
02305 if (sel->star() != NULL)
02306 lua_pushnumber(l, sel->star()->getAbsoluteMagnitude());
02307 else
02308 lua_pushnil(l);
02309
02310 return 1;
02311 }
02312
02313 static int object_mark(lua_State* l)
02314 {
02315 checkArgs(l, 1, 4, "No arguments expected to function object:mark");
02316
02317 Selection* sel = this_object(l);
02318 CelestiaCore* appCore = getAppCore(l, AllErrors);
02319
02320 Color markColor(0.0f, 1.0f, 0.0f);
02321 const char* colorString = safeGetString(l, 2, WrongType, "First argument to object:mark must be a string");
02322 if (colorString != NULL)
02323 Color::parse(colorString, markColor);
02324
02325 Marker::Symbol markSymbol = Marker::Diamond;
02326 const char* markerString = safeGetString(l, 3, WrongType, "Second argument to object:mark must be a string");
02327 if (markerString != NULL)
02328 markSymbol = parseMarkerSymbol(markerString);
02329
02330 float markSize = (float)safeGetNumber(l, 4, WrongType, "Third arg to object:mark must be a number", 10.0);
02331 if (markSize < 1.0f)
02332 markSize = 1.0f;
02333 else if (markSize > 10000.0f)
02334 markSize = 10000.0f;
02335
02336 Simulation* sim = appCore->getSimulation();
02337 sim->getUniverse()->markObject(*sel, markSize,
02338 markColor, markSymbol, 1);
02339
02340 return 0;
02341 }
02342
02343 static int object_unmark(lua_State* l)
02344 {
02345 checkArgs(l, 1, 1, "No arguments expected to function object:unmark");
02346
02347 Selection* sel = this_object(l);
02348 CelestiaCore* appCore = getAppCore(l, AllErrors);
02349
02350 Simulation* sim = appCore->getSimulation();
02351 sim->getUniverse()->unmarkObject(*sel, 1);
02352
02353 return 0;
02354 }
02355
02356
02357
02358 static int object_getposition(lua_State* l)
02359 {
02360 checkArgs(l, 1, 2, "Expected no or one argument to object:getposition");
02361
02362 Selection* sel = this_object(l);
02363 CelestiaCore* appCore = getAppCore(l, AllErrors);
02364
02365 double t = safeGetNumber(l, 2, WrongType, "Time expected as argument to object:getposition",
02366 appCore->getSimulation()->getTime());
02367 position_new(l, sel->getPosition(t));
02368
02369 return 1;
02370 }
02371
02372 static int object_getchildren(lua_State* l)
02373 {
02374 checkArgs(l, 1, 1, "No arguments expected for object:getchildren()");
02375
02376 Selection* sel = this_object(l);
02377 CelestiaCore* appCore = getAppCore(l, AllErrors);
02378
02379 Simulation* sim = appCore->getSimulation();
02380
02381 lua_newtable(l);
02382 if (sel->star() != NULL)
02383 {
02384 SolarSystemCatalog* solarSystemCatalog = sim->getUniverse()->getSolarSystemCatalog();
02385 SolarSystemCatalog::iterator iter = solarSystemCatalog->find(sel->star()->getCatalogNumber());
02386 if (iter != solarSystemCatalog->end())
02387 {
02388 SolarSystem* solarSys = iter->second;
02389 for (int i = 0; i < solarSys->getPlanets()->getSystemSize(); i++)
02390 {
02391 Body* body = solarSys->getPlanets()->getBody(i);
02392 Selection satSel(body);
02393 object_new(l, satSel);
02394 lua_rawseti(l, -2, i + 1);
02395 }
02396 }
02397 }
02398 else if (sel->body() != NULL)
02399 {
02400 const PlanetarySystem* satellites = sel->body()->getSatellites();
02401 if (satellites != NULL && satellites->getSystemSize() != 0)
02402 {
02403 for (int i = 0; i < satellites->getSystemSize(); i++)
02404 {
02405 Body* body = satellites->getBody(i);
02406 Selection satSel(body);
02407 object_new(l, satSel);
02408 lua_rawseti(l, -2, i + 1);
02409 }
02410 }
02411 }
02412
02413 return 1;
02414 }
02415
02416 static int object_preloadtexture(lua_State* l)
02417 {
02418 checkArgs(l, 1, 1, "No argument expected to object:preloadtexture");
02419 CelestiaCore* appCore = getAppCore(l, AllErrors);
02420
02421 Renderer* renderer = appCore->getRenderer();
02422 Selection* sel = this_object(l);
02423 if (sel->body() != NULL && renderer != NULL)
02424 {
02425 LuaState* luastate = getLuaStateObject(l);
02426
02427 double timeToTimeout = luastate->timeout - luastate->getTime();
02428
02429 renderer->loadTextures(sel->body());
02430
02431
02432 luastate->timeout = luastate->getTime() + timeToTimeout - 0.1;
02433 }
02434 return 0;
02435 }
02436
02437 static void CreateObjectMetaTable(lua_State* l)
02438 {
02439 CreateClassMetatable(l, _Object);
02440
02441 RegisterMethod(l, "__tostring", object_tostring);
02442 RegisterMethod(l, "radius", object_radius);
02443 RegisterMethod(l, "type", object_type);
02444 RegisterMethod(l, "spectraltype", object_spectraltype);
02445 RegisterMethod(l, "getinfo", object_getinfo);
02446 RegisterMethod(l, "absmag", object_absmag);
02447 RegisterMethod(l, "name", object_name);
02448 RegisterMethod(l, "mark", object_mark);
02449 RegisterMethod(l, "unmark", object_unmark);
02450 RegisterMethod(l, "getposition", object_getposition);
02451 RegisterMethod(l, "getchildren", object_getchildren);
02452 RegisterMethod(l, "preloadtexture", object_preloadtexture);
02453
02454 lua_pop(l, 1);
02455 }
02456
02457
02458 static int observer_new(lua_State* l, Observer* o)
02459 {
02460 Observer** ud = static_cast<Observer**>(lua_newuserdata(l, sizeof(Observer*)));
02461 *ud = o;
02462
02463 SetClass(l, _Observer);
02464
02465 return 1;
02466 }
02467
02468 static Observer* to_observer(lua_State* l, int index)
02469 {
02470 Observer** o = static_cast<Observer**>(lua_touserdata(l, index));
02471 CelestiaCore* appCore = getAppCore(l, AllErrors);
02472
02473
02474 if (o != NULL && getViewByObserver(appCore, *o) != NULL)
02475 {
02476 return *o;
02477 }
02478 return NULL;
02479 }
02480
02481 static Observer* this_observer(lua_State* l)
02482 {
02483 Observer* obs = to_observer(l, 1);
02484 if (obs == NULL)
02485 {
02486 doError(l, "Bad observer object (maybe tried to access a deleted view?)!");
02487 }
02488
02489 return obs;
02490 }
02491
02492
02493 static int observer_isvalid(lua_State* l)
02494 {
02495 checkArgs(l, 1, 1, "No arguments expected for observer:isvalid()");
02496 lua_pushboolean(l, to_observer(l, 1) != NULL);
02497 return 1;
02498 }
02499
02500 static int observer_tostring(lua_State* l)
02501 {
02502 lua_pushstring(l, "[Observer]");
02503
02504 return 1;
02505 }
02506
02507 static int observer_setposition(lua_State* l)
02508 {
02509 checkArgs(l, 2, 2, "One argument required for setpos");
02510
02511 Observer* o = this_observer(l);
02512
02513 UniversalCoord* uc = to_position(l,2);
02514 if (uc == NULL)
02515 {
02516 doError(l, "Argument to observer:setposition must be a position");
02517 }
02518 o->setPosition(*uc);
02519 return 0;
02520 }
02521
02522 static int observer_setorientation(lua_State* l)
02523 {
02524 checkArgs(l, 2, 2, "One argument required for setorientation");
02525
02526 Observer* o = this_observer(l);
02527
02528 Quatd* q = to_rotation(l,2);
02529 if (q == NULL)
02530 {
02531 doError(l, "Argument to observer:setorientation must be a rotation");
02532 }
02533 o->setOrientation(*q);
02534 return 0;
02535 }
02536
02537 static int observer_getorientation(lua_State* l)
02538 {
02539 checkArgs(l, 1, 1, "No arguments expected to observer:getorientation()");
02540
02541 Observer* o = this_observer(l);
02542 Quatf q = o->getOrientation();
02543 rotation_new(l, Quatd(q.w, q.x, q.y, q.z));
02544
02545 return 1;
02546 }
02547
02548 static int observer_rotate(lua_State* l)
02549 {
02550 checkArgs(l, 2, 2, "One argument required for rotate");
02551
02552 Observer* o = this_observer(l);
02553
02554 Quatd* q = to_rotation(l,2);
02555 if (q == NULL)
02556 {
02557 doError(l, "Argument to observer:setpos must be a rotation");
02558 }
02559 Quatf qf((float) q->w, (float) q->x, (float) q->y, (float) q->z);
02560 o->rotate(qf);
02561 return 0;
02562 }
02563
02564 static int observer_lookat(lua_State* l)
02565 {
02566 checkArgs(l, 3, 4, "Two or three arguments required for lookat");
02567 int argc = lua_gettop(l);
02568
02569 Observer* o = this_observer(l);
02570
02571 UniversalCoord* from = NULL;
02572 UniversalCoord* to = NULL;
02573 Vec3d* upd = NULL;
02574 if (argc == 3)
02575 {
02576 to = to_position(l, 2);
02577 upd = to_vector(l, 3);
02578 if (to == NULL)
02579 {
02580 doError(l, "Argument 1 (of 2) to observer:lookat must be of type position");
02581 }
02582 }
02583 else
02584 if (argc == 4)
02585 {
02586 from = to_position(l, 2);
02587 to = to_position(l, 3);
02588 upd = to_vector(l, 4);
02589
02590 if (to == NULL || from == NULL)
02591 {
02592 doError(l, "Argument 1 and 2 (of 3) to observer:lookat must be of type position");
02593 }
02594 }
02595 if (upd == NULL)
02596 {
02597 doError(l, "Last argument to observer:lookat must be of type vector");
02598 }
02599 Vec3d nd;
02600 if (from == NULL)
02601 {
02602 nd = (*to) - o->getPosition();
02603 }
02604 else
02605 {
02606 nd = (*to) - (*from);
02607 }
02608
02609 Vec3f up = Vec3f((float) upd->x, (float) upd->y, (float) upd->z);
02610 Vec3f n = Vec3f((float) nd.x, (float) nd.y, (float) nd.z);
02611
02612 n.normalize();
02613 Vec3f v = n ^ up;
02614 v.normalize();
02615 Vec3f u = v ^ n;
02616 Quatf qf = Quatf(Mat3f(v, u, -n));
02617 o->setOrientation(qf);
02618 return 0;
02619 }
02620
02621 static int observer_gototable(lua_State* l)
02622 {
02623 checkArgs(l, 2, 2, "Expected one table as argument to goto");
02624
02625 Observer* o = this_observer(l);
02626 if (!lua_istable(l, 2))
02627 {
02628 lua_pushstring(l, "Argument to goto must be a table");
02629 }
02630
02631 Observer::JourneyParams jparams;
02632 jparams.duration = 5.0;
02633 jparams.from = o->getSituation().translation;
02634 jparams.to = o->getSituation().translation;
02635 jparams.initialOrientation = o->getOrientation();
02636 jparams.finalOrientation = o->getOrientation();
02637 jparams.startInterpolation = 0.25;
02638 jparams.endInterpolation = 0.75;
02639 jparams.accelTime = 0.5;
02640 jparams.traj = Observer::Linear;
02641
02642 lua_pushstring(l, "duration");
02643 lua_gettable(l, 2);
02644 jparams.duration = safeGetNumber(l, 3, NoErrors, "", 5.0);
02645 lua_settop(l, 2);
02646
02647 lua_pushstring(l, "from");
02648 lua_gettable(l, 2);
02649 UniversalCoord* from = to_position(l, 3);
02650 if (from != NULL)
02651 jparams.from = *from;
02652 lua_settop(l, 2);
02653
02654 lua_pushstring(l, "to");
02655 lua_gettable(l, 2);
02656 UniversalCoord* to = to_position(l, 3);
02657 if (to != NULL)
02658 jparams.to = *to;
02659 lua_settop(l, 2);
02660
02661 lua_pushstring(l, "initialOrientation");
02662 lua_gettable(l, 2);
02663 Quatd* rot1 = to_rotation(l, 3);
02664 if (rot1 != NULL)
02665 jparams.initialOrientation = Quatf((float) rot1->w, (float) rot1->x, (float) rot1->y, (float) rot1->z);
02666 lua_settop(l, 2);
02667
02668 lua_pushstring(l, "finalOrientation");
02669 lua_gettable(l, 2);
02670 Quatd* rot2 = to_rotation(l, 3);
02671 if (rot2 != NULL)
02672 jparams.finalOrientation = Quatf((float) rot2->w, (float) rot2->x, (float) rot2->y, (float) rot2->z);
02673 lua_settop(l, 2);
02674
02675 lua_pushstring(l, "startInterpolation");
02676 lua_gettable(l, 2);
02677 jparams.startInterpolation = safeGetNumber(l, 3, NoErrors, "", 0.25);
02678 lua_settop(l, 2);
02679
02680 lua_pushstring(l, "endInterpolation");
02681 lua_gettable(l, 2);
02682 jparams.endInterpolation = safeGetNumber(l, 3, NoErrors, "", 0.75);
02683 lua_settop(l, 2);
02684
02685 lua_pushstring(l, "accelTime");
02686 lua_gettable(l, 2);
02687 jparams.accelTime = safeGetNumber(l, 3, NoErrors, "", 0.5);
02688 lua_settop(l, 2);
02689
02690 jparams.duration = max(0.0, jparams.duration);
02691 jparams.accelTime = min(1.0, max(0.1, jparams.accelTime));
02692 jparams.startInterpolation = min(1.0, max(0.0, jparams.startInterpolation));
02693 jparams.endInterpolation = min(1.0, max(0.0, jparams.endInterpolation));
02694
02695
02696 FrameOfReference tmp = o->getFrame();
02697 o->setFrame(FrameOfReference());
02698 o->gotoJourney(jparams);
02699 o->setFrame(tmp);
02700 return 0;
02701 }
02702
02703
02704
02705 static int observer_goto(lua_State* l)
02706 {
02707 if (lua_gettop(l) == 2 && lua_istable(l, 2))
02708 {
02709
02710 return observer_gototable(l);
02711 }
02712 checkArgs(l, 1, 5, "One to four arguments expected to observer:goto");
02713
02714 Observer* o = this_observer(l);
02715
02716 Selection* sel = to_object(l, 2);
02717 UniversalCoord* uc = to_position(l, 2);
02718 if (sel == NULL && uc == NULL)
02719 {
02720 doError(l, "First arg to observer:goto must be object or position");
02721 }
02722
02723 double travelTime = safeGetNumber(l, 3, WrongType, "Second arg to observer:goto must be a number", 5.0);
02724 double startInter = safeGetNumber(l, 4, WrongType, "Third arg to observer:goto must be a number", 0.25);
02725 double endInter = safeGetNumber(l, 5, WrongType, "Fourth arg to observer:goto must be a number", 0.75);
02726 if (startInter < 0 || startInter > 1) startInter = 0.25;
02727 if (endInter < 0 || endInter > 1) startInter = 0.75;
02728
02729
02730 if (sel != NULL)
02731 {
02732 o->gotoSelection(*sel, travelTime, startInter, endInter, Vec3f(0, 1, 0), astro::ObserverLocal);
02733 }
02734 else
02735 {
02736 RigidTransform rt = o->getSituation();
02737 rt.translation = *uc;
02738 o->gotoLocation(rt, travelTime);
02739 }
02740
02741 return 0;
02742 }
02743
02744 static int observer_gotolonglat(lua_State* l)
02745 {
02746 checkArgs(l, 2, 7, "One to five arguments expected to observer:gotolonglat");
02747
02748 Observer* o = this_observer(l);
02749
02750 Selection* sel = to_object(l, 2);
02751 if (sel == NULL)
02752 {
02753 doError(l, "First arg to observer:gotolonglat must be an object");
02754 }
02755 double defaultDistance = sel->radius() * 5.0;
02756
02757 double longitude = safeGetNumber(l, 3, WrongType, "Second arg to observer:gotolonglat must be a number", 0.0);
02758 double latitude = safeGetNumber(l, 4, WrongType, "Third arg to observer:gotolonglat must be a number", 0.0);
02759 double distance = safeGetNumber(l, 5, WrongType, "Fourth arg to observer:gotolonglat must be a number", defaultDistance);
02760 double travelTime = safeGetNumber(l, 6, WrongType, "Fifth arg to observer:gotolonglat must be a number", 5.0);
02761
02762 distance = distance / KM_PER_LY;
02763
02764 Vec3f up(0.0f, 1.0f, 0.0f);
02765 if (lua_gettop(l) >= 7)
02766 {
02767 Vec3d* uparg = to_vector(l, 7);
02768 if (uparg == NULL)
02769 {
02770 doError(l, "Sixth argument to observer:gotolonglat must be a vector");
02771 }
02772 up = Vec3f((float)uparg->x, (float)uparg->y, (float)uparg->z);
02773 }
02774 o->gotoSelectionLongLat(*sel, travelTime, distance, (float)longitude, (float)latitude, up);
02775
02776 return 0;
02777 }
02778
02779
02780 static int observer_gotolocation(lua_State* l)
02781 {
02782 checkArgs(l, 2, 3,"Expected one or two arguments to observer:gotolocation");
02783
02784 Observer* o = this_observer(l);
02785
02786 double travelTime = safeGetNumber(l, 3, WrongType, "Second arg to observer:gotolocation must be a number", 5.0);
02787 if (travelTime < 0)
02788 travelTime = 0.0;
02789
02790 UniversalCoord* uc = to_position(l, 2);
02791 if (uc != NULL)
02792 {
02793 RigidTransform rt = o->getSituation();
02794 rt.translation = *uc;
02795 o->gotoLocation(rt, travelTime);
02796 }
02797 else
02798 {
02799 doError(l, "First arg to observer:gotolocation must be a position");
02800 }
02801
02802 return 0;
02803 }
02804
02805 static int observer_gotodistance(lua_State* l)
02806 {
02807 checkArgs(l, 2, 5, "One to four arguments expected to observer:gotodistance");
02808
02809 Observer* o = this_observer(l);
02810 Selection* sel = to_object(l, 2);
02811 if (sel == NULL)
02812 {
02813 doError(l, "First arg to observer:gotodistance must be object");
02814 }
02815
02816 double distance = safeGetNumber(l, 3, WrongType, "Second arg to observer:gotodistance must be a number", 20000);
02817 double travelTime = safeGetNumber(l, 4, WrongType, "Third arg to observer:gotodistance must be a number", 5.0);
02818
02819 Vec3f up(0,1,0);
02820 if (lua_gettop(l) > 4)
02821 {
02822 Vec3d* up_arg = to_vector(l, 5);
02823 if (up_arg == NULL)
02824 {
02825 doError(l, "Fourth arg to observer:gotodistance must be a vector");
02826 }
02827 up.x = (float)up_arg->x;
02828 up.y = (float)up_arg->y;
02829 up.z = (float)up_arg->z;
02830 }
02831
02832 o->gotoSelection(*sel, travelTime, astro::kilometersToLightYears(distance), up, astro::Universal);
02833
02834 return 0;
02835 }
02836
02837 static int observer_gotosurface(lua_State* l)
02838 {
02839 checkArgs(l, 2, 3, "One to two arguments expected to observer:gotosurface");
02840
02841 Observer* o = this_observer(l);
02842 Selection* sel = to_object(l, 2);
02843 if (sel == NULL)
02844 {
02845 doError(l, "First arg to observer:gotosurface must be object");
02846 }
02847
02848 double travelTime = safeGetNumber(l, 3, WrongType, "Second arg to observer:gotosurface must be a number", 5.0);
02849
02850
02851 o->geosynchronousFollow(*sel);
02852 o->gotoSurface(*sel, travelTime);
02853
02854 return 0;
02855 }
02856
02857 static int observer_center(lua_State* l)
02858 {
02859 checkArgs(l, 2, 3, "Expected one or two arguments for to observer:center");
02860
02861 Observer* o = this_observer(l);
02862 Selection* sel = to_object(l, 2);
02863 if (sel == NULL)
02864 {
02865 doError(l, "First argument to observer:center must be an object");
02866 }
02867 double travelTime = safeGetNumber(l, 3, WrongType, "Second arg to observer:center must be a number", 5.0);
02868
02869 o->centerSelection(*sel, travelTime);
02870
02871 return 0;
02872 }
02873
02874 static int observer_centerorbit(lua_State* l)
02875 {
02876 checkArgs(l, 2, 3, "Expected one or two arguments for to observer:center");
02877
02878 Observer* o = this_observer(l);
02879 Selection* sel = to_object(l, 2);
02880 if (sel == NULL)
02881 {
02882 doError(l, "First argument to observer:centerorbit must be an object");
02883 }
02884 double travelTime = safeGetNumber(l, 3, WrongType, "Second arg to observer:centerorbit must be a number", 5.0);
02885
02886 o->centerSelectionCO(*sel, travelTime);
02887
02888 return 0;
02889 }
02890
02891 static int observer_cancelgoto(lua_State* l)
02892 {
02893 checkArgs(l, 1, 1, "Expected no arguments to observer:cancelgoto");
02894
02895 Observer* o = this_observer(l);
02896 o->cancelMotion();
02897
02898 return 0;
02899 }
02900
02901 static int observer_follow(lua_State* l)
02902 {
02903 checkArgs(l, 2, 2, "One argument expected for observer:follow");
02904
02905 Observer* o = this_observer(l);
02906 Selection* sel = to_object(l, 2);
02907 if (sel == NULL)
02908 {
02909 doError(l, "First argument to observer:follow must be an object");
02910 }
02911 o->follow(*sel);
02912
02913 return 0;
02914 }
02915
02916 static int observer_synchronous(lua_State* l)
02917 {
02918 checkArgs(l, 2, 2, "One argument expected for observer:synchronous");
02919
02920 Observer* o = this_observer(l);
02921 Selection* sel = to_object(l, 2);
02922 if (sel == NULL)
02923 {
02924 doError(l, "First argument to observer:synchronous must be an object");
02925 }
02926 o->geosynchronousFollow(*sel);
02927
02928 return 0;
02929 }
02930
02931 static int observer_lock(lua_State* l)
02932 {
02933 checkArgs(l, 2, 2, "One argument expected for observer:lock");
02934
02935 Observer* o = this_observer(l);
02936 Selection* sel = to_object(l, 2);
02937 if (sel == NULL)
02938 {
02939 doError(l, "First argument to observer:phaseLock must be an object");
02940 }
02941 o->phaseLock(*sel);
02942
02943 return 0;
02944 }
02945
02946 static int observer_chase(lua_State* l)
02947 {
02948 checkArgs(l, 2, 2, "One argument expected for observer:chase");
02949
02950 Observer* o = this_observer(l);
02951 Selection* sel = to_object(l, 2);
02952 if (sel == NULL)
02953 {
02954 doError(l, "First argument to observer:chase must be an object");
02955 }
02956 o->chase(*sel);
02957
02958 return 0;
02959 }
02960
02961 static int observer_track(lua_State* l)
02962 {
02963 checkArgs(l, 2, 2, "One argument expected for observer:track");
02964
02965 Observer* o = this_observer(l);
02966
02967
02968 if (lua_isnil(l, 2))
02969 {
02970 o->setTrackedObject(Selection());
02971 }
02972 else
02973 {
02974
02975 Selection* sel = to_object(l, 2);
02976 if (sel == NULL)
02977 {
02978 doError(l, "First argument to observer:center must be an object");
02979 }
02980 o->setTrackedObject(*sel);
02981 }
02982
02983 return 0;
02984 }
02985
02986
02987
02988 static int observer_travelling(lua_State* l)
02989 {
02990 checkArgs(l, 1, 1, "No arguments expected to observer:travelling");
02991
02992 Observer* o = this_observer(l);
02993 if (o->getMode() == Observer::Travelling)
02994 lua_pushboolean(l, 1);
02995 else
02996 lua_pushboolean(l, 0);
02997
02998 return 1;
02999 }
03000
03001
03002 static int observer_gettime(lua_State* l)
03003 {
03004 checkArgs(l, 1, 1, "No arguments expected to observer:gettime");
03005
03006 Observer* o = this_observer(l);
03007 lua_pushnumber(l, o->getTime());
03008
03009 return 1;
03010 }
03011
03012
03013 static int observer_getposition(lua_State* l)
03014 {
03015 checkArgs(l, 1, 1, "No arguments expected to observer:getposition");
03016
03017 Observer* o = this_observer(l);
03018 position_new(l, o->getPosition());
03019
03020 return 1;
03021 }
03022
03023 static int observer_getsurface(lua_State* l)
03024 {
03025 checkArgs(l, 1, 1, "One argument expected to observer:getsurface()");
03026
03027 Observer* obs = this_observer(l);
03028 lua_pushstring(l, obs->getDisplayedSurface().c_str());
03029
03030 return 1;
03031 }
03032
03033 static int observer_setsurface(lua_State* l)
03034 {
03035 checkArgs(l, 2, 2, "One argument expected to observer:setsurface()");
03036
03037 Observer* obs = this_observer(l);
03038 const char* s = lua_tostring(l, 2);
03039
03040 if (s == NULL)
03041 obs->setDisplayedSurface("");
03042 else
03043 obs->setDisplayedSurface(s);
03044
03045 return 0;
03046 }
03047
03048 static int observer_getframe(lua_State* l)
03049 {
03050 checkArgs(l, 1, 1, "No arguments expected for observer:getframe()");
03051
03052 Observer* obs = this_observer(l);
03053
03054 FrameOfReference frame = obs->getFrame();
03055 frame_new(l, frame);
03056 return 1;
03057 }
03058
03059 static int observer_setframe(lua_State* l)
03060 {
03061 checkArgs(l, 2, 2, "One argument required for observer:setframe()");
03062
03063 Observer* obs = this_observer(l);
03064
03065 FrameOfReference* frame;
03066 frame = to_frame(l, 2);
03067 if (frame != NULL)
03068 {
03069 obs->setFrame(*frame);
03070 }
03071 else
03072 {
03073 doError(l, "Argument to observer:setframe must be a frame");
03074 }
03075 return 0;
03076 }
03077
03078 static int observer_setspeed(lua_State* l)
03079 {
03080 checkArgs(l, 2, 2, "One argument required for observer:setspeed()");
03081
03082 Observer* obs = this_observer(l);
03083
03084 double speed = safeGetNumber(l, 2, AllErrors, "First argument to observer:setspeed must be a number");
03085 obs->setTargetSpeed((float)speed);
03086 return 0;
03087 }
03088
03089 static int observer_getspeed(lua_State* l)
03090 {
03091 checkArgs(l, 1, 1, "No argument expected for observer:getspeed()");
03092
03093 Observer* obs = this_observer(l);
03094
03095 lua_pushnumber(l, (lua_Number)obs->getTargetSpeed());
03096 return 1;
03097 }
03098
03099 static int observer_setfov(lua_State* l)
03100 {
03101 checkArgs(l, 2, 2, "One argument expected to observer:setfov()");
03102
03103 Observer* obs = this_observer(l);
03104 double fov = safeGetNumber(l, 2, AllErrors, "Argument to observer:setfov() must be a number");
03105 if ((fov >= degToRad(0.001f)) && (fov <= degToRad(120.0f)))
03106 {
03107 obs->setFOV((float) fov);
03108 getAppCore(l, AllErrors)->setZoomFromFOV();
03109 }
03110 return 0;
03111 }
03112
03113 static int observer_getfov(lua_State* l)
03114 {
03115 checkArgs(l, 1, 1, "No argument expected to observer:getfov()");
03116
03117 Observer* obs = this_observer(l);
03118 lua_pushnumber(l, obs->getFOV());
03119 return 1;
03120 }
03121
03122 static int observer_splitview(lua_State* l)
03123 {
03124 checkArgs(l, 2, 3, "One or two arguments expected for observer:splitview()");
03125
03126 Observer* obs = this_observer(l);
03127 CelestiaCore* appCore = getAppCore(l, AllErrors);
03128 const char* splitType = safeGetString(l, 2, AllErrors, "First argument to observer:splitview() must be a string");
03129 View::Type type = (compareIgnoringCase(splitType, "h") == 0) ? View::HorizontalSplit : View::VerticalSplit;
03130 double splitPos = safeGetNumber(l, 3, WrongType, "Number expected as argument to observer:splitview()", 0.5);
03131 if (splitPos < 0.1)
03132 splitPos = 0.1;
03133 if (splitPos > 0.9)
03134 splitPos = 0.9;
03135 View* view = getViewByObserver(appCore, obs);
03136 appCore->splitView(type, view, (float)splitPos);
03137 return 0;
03138 }
03139
03140 static int observer_deleteview(lua_State* l)
03141 {
03142 checkArgs(l, 1, 1, "No argument expected for observer:deleteview()");
03143
03144 Observer* obs = this_observer(l);
03145 CelestiaCore* appCore = getAppCore(l, AllErrors);
03146 View* view = getViewByObserver(appCore, obs);
03147 appCore->deleteView(view);
03148 return 0;
03149 }
03150
03151 static int observer_singleview(lua_State* l)
03152 {
03153 checkArgs(l, 1, 1, "No argument expected for observer:singleview()");
03154
03155 Observer* obs = this_observer(l);
03156 CelestiaCore* appCore = getAppCore(l, AllErrors);
03157 View* view = getViewByObserver(appCore, obs);
03158 appCore->singleView(view);
03159 return 0;
03160 }
03161
03162 static int observer_equal(lua_State* l)
03163 {
03164 checkArgs(l, 2, 2, "Wrong number of arguments for comparison!");
03165
03166 Observer* o1 = this_observer(l);
03167 Observer* o2 = to_observer(l, 2);
03168
03169 lua_pushboolean(l, (o1 == o2));
03170 return 1;
03171 }
03172
03173 static int observer_setlocationflags(lua_State* l)
03174 {
03175 checkArgs(l, 2, 2, "One argument expected for observer:setlocationflags()");
03176 Observer* obs = this_observer(l);
03177 if (!lua_istable(l, 2))
03178 {
03179 doError(l, "Argument to observer:setlocationflags() must be a table");
03180 }
03181
03182 lua_pushnil(l);
03183 int locationFlags = obs->getLocationFilter();
03184 while (lua_next(l, -2) != 0)
03185 {
03186 string key;
03187 bool value = false;
03188 if (lua_isstring(l, -2))
03189 {
03190 key = lua_tostring(l, -2);
03191 }
03192 else
03193 {
03194 doError(l, "Keys in table-argument to observer:setlocationflags() must be strings");
03195 }
03196 if (lua_isboolean(l, -1))
03197 {
03198 value = lua_toboolean(l, -1);
03199 }
03200 else
03201 {
03202 doError(l, "Values in table-argument to observer:setlocationflags() must be boolean");
03203 }
03204 if (LocationFlagMap.count(key) == 0)
03205 {
03206 cerr << "Unknown key: " << key << "\n";
03207 }
03208 else
03209 {
03210 int flag = LocationFlagMap[key];
03211 if (value)
03212 {
03213 locationFlags |= flag;
03214 }
03215 else
03216 {
03217 locationFlags &= ~flag;
03218 }
03219 }
03220 lua_pop(l,1);
03221 }
03222 obs->setLocationFilter(locationFlags);
03223 return 0;
03224 }
03225
03226 static int observer_getlocationflags(lua_State* l)
03227 {
03228 checkArgs(l, 1, 1, "No arguments expected for observer:getlocationflags()");
03229 Observer* obs = this_observer(l);
03230 lua_newtable(l);
03231 FlagMap::const_iterator it = LocationFlagMap.begin();
03232 const int locationFlags = obs->getLocationFilter();
03233 while (it != LocationFlagMap.end())
03234 {
03235 string key = it->first;
03236 lua_pushstring(l, key.c_str());
03237 lua_pushboolean(l, (it->second & locationFlags) != 0);
03238 lua_settable(l,-3);
03239 it++;
03240 }
03241 return 1;
03242 }
03243
03244 static void CreateObserverMetaTable(lua_State* l)
03245 {
03246 CreateClassMetatable(l, _Observer);
03247
03248 RegisterMethod(l, "__tostring", observer_tostring);
03249 RegisterMethod(l, "isvalid", observer_isvalid);
03250 RegisterMethod(l, "goto", observer_goto);
03251 RegisterMethod(l, "gotolonglat", observer_gotolonglat);
03252 RegisterMethod(l, "gotolocation", observer_gotolocation);
03253 RegisterMethod(l, "gotodistance", observer_gotodistance);
03254 RegisterMethod(l, "gotosurface", observer_gotosurface);
03255 RegisterMethod(l, "cancelgoto", observer_cancelgoto);
03256 RegisterMethod(l, "setposition", observer_setposition);
03257 RegisterMethod(l, "lookat", observer_lookat);
03258 RegisterMethod(l, "setorientation", observer_setorientation);
03259 RegisterMethod(l, "getorientation", observer_getorientation);
03260 RegisterMethod(l, "getspeed", observer_getspeed);
03261 RegisterMethod(l, "setspeed", observer_setspeed);
03262 RegisterMethod(l, "getfov", observer_getfov);
03263 RegisterMethod(l, "setfov", observer_setfov);
03264 RegisterMethod(l, "rotate", observer_rotate);
03265 RegisterMethod(l, "center", observer_center);
03266 RegisterMethod(l, "centerorbit", observer_centerorbit);
03267 RegisterMethod(l, "follow", observer_follow);
03268 RegisterMethod(l, "synchronous", observer_synchronous);
03269 RegisterMethod(l, "chase", observer_chase);
03270 RegisterMethod(l, "lock", observer_lock);
03271 RegisterMethod(l, "track", observer_track);
03272 RegisterMethod(l, "travelling", observer_travelling);
03273 RegisterMethod(l, "getframe", observer_getframe);
03274 RegisterMethod(l, "setframe", observer_setframe);
03275 RegisterMethod(l, "gettime", observer_gettime);
03276 RegisterMethod(l, "getposition", observer_getposition);
03277 RegisterMethod(l, "getsurface", observer_getsurface);
03278 RegisterMethod(l, "setsurface", observer_setsurface);
03279 RegisterMethod(l, "splitview", observer_splitview);
03280 RegisterMethod(l, "deleteview", observer_deleteview);
03281 RegisterMethod(l, "singleview", observer_singleview);
03282 RegisterMethod(l, "getlocationflags", observer_getlocationflags);
03283 RegisterMethod(l, "setlocationflags", observer_setlocationflags);
03284 RegisterMethod(l, "__eq", observer_equal);
03285
03286 lua_pop(l, 1);
03287 }
03288
03289
03290
03291
03292
03293 static int celscript_from_string(lua_State* l, string& script_text)
03294 {
03295 #ifdef HAVE_SSTREAM
03296 istringstream scriptfile(script_text);
03297 #else
03298 istrstream scriptfile(script_text.c_str());
03299 #endif
03300 CelestiaCore* appCore = getAppCore(l, AllErrors);
03301 CelScriptWrapper* celscript = new CelScriptWrapper(*appCore, scriptfile);
03302 if (celscript->getErrorMessage() != "")
03303 {
03304 string error = celscript->getErrorMessage();
03305 delete celscript;
03306 doError(l, error.c_str());
03307 }
03308 else
03309 {
03310 CelScriptWrapper** ud = reinterpret_cast<CelScriptWrapper**>(lua_newuserdata(l, sizeof(CelScriptWrapper*)));
03311 *ud = celscript;
03312 SetClass(l, _CelScript);
03313 }
03314
03315 return 1;
03316 }
03317
03318 static CelScriptWrapper* this_celscript(lua_State* l)
03319 {
03320 CelScriptWrapper** script = static_cast<CelScriptWrapper**>(CheckUserData(l, 1, _CelScript));
03321 if (script == NULL)
03322 {
03323 doError(l, "Bad CEL-script object!");
03324 }
03325 return *script;
03326 }
03327
03328 static int celscript_tostring(lua_State* l)
03329 {
03330 lua_pushstring(l, "[Celscript]");
03331
03332 return 1;
03333 }
03334
03335 static int celscript_tick(lua_State* l)
03336 {
03337 CelScriptWrapper* script = this_celscript(l);
03338 LuaState* stateObject = getLuaStateObject(l);
03339 double t = stateObject->getTime();
03340 lua_pushboolean(l, !(script->tick(t)) );
03341 return 1;
03342 }
03343
03344 static int celscript_gc(lua_State* l)
03345 {
03346 CelScriptWrapper* script = this_celscript(l);
03347 delete script;
03348 return 0;
03349 }
03350
03351
03352 static void CreateCelscriptMetaTable(lua_State* l)
03353 {
03354 CreateClassMetatable(l, _CelScript);
03355
03356 RegisterMethod(l, "__tostring", celscript_tostring);
03357 RegisterMethod(l, "tick", celscript_tick);
03358 RegisterMethod(l, "__gc", celscript_gc);
03359
03360 lua_pop(l, 1);
03361 }
03362
03363
03364
03365 static int celestia_new(lua_State* l, CelestiaCore* appCore)
03366 {
03367 CelestiaCore** ud = reinterpret_cast<CelestiaCore**>(lua_newuserdata(l, sizeof(CelestiaCore*)));
03368 *ud = appCore;
03369
03370 SetClass(l, _Celestia);
03371
03372 return 1;
03373 }
03374
03375 static CelestiaCore* to_celestia(lua_State* l, int index)
03376 {
03377 CelestiaCore** appCore = static_cast<CelestiaCore**>(CheckUserData(l, index, _Celestia));
03378 if (appCore == NULL)
03379 return NULL;
03380 else
03381 return *appCore;
03382 }
03383
03384 static CelestiaCore* this_celestia(lua_State* l)
03385 {
03386 CelestiaCore* appCore = to_celestia(l, 1);
03387 if (appCore == NULL)
03388 {
03389 doError(l, "Bad celestia object!");
03390 }
03391
03392 return appCore;
03393 }
03394
03395
03396 static int celestia_flash(lua_State* l)
03397 {
03398 checkArgs(l, 2, 3, "One or two arguments expected to function celestia:flash");
03399
03400 CelestiaCore* appCore = this_celestia(l);
03401 const char* s = safeGetString(l, 2, AllErrors, "First argument to celestia:flash must be a string");
03402 double duration = safeGetNumber(l, 3, WrongType, "Second argument to celestia:flash must be a number", 1.5);
03403 if (duration < 0.0)
03404 {
03405 duration = 1.5;
03406 }
03407
03408 appCore->flash(s, duration);
03409
03410 return 0;
03411 }
03412
03413 static int celestia_print(lua_State* l)
03414 {
03415 checkArgs(l, 2, 7, "One to six arguments expected to function celestia:print");
03416
03417 CelestiaCore* appCore = this_celestia(l);
03418 const char* s = safeGetString(l, 2, AllErrors, "First argument to celestia:print must be a string");
03419 double duration = safeGetNumber(l, 3, WrongType, "Second argument to celestia:print must be a number", 1.5);
03420 int horig = (int)safeGetNumber(l, 4, WrongType, "Third argument to celestia:print must be a number", -1.0);
03421 int vorig = (int)safeGetNumber(l, 5, WrongType, "Fourth argument to celestia:print must be a number", -1.0);
03422 int hoff = (int)safeGetNumber(l, 6, WrongType, "Fifth argument to celestia:print must be a number", 0.0);
03423 int voff = (int)safeGetNumber(l, 7, WrongType, "Sixth argument to celestia:print must be a number", 5.0);
03424
03425 if (duration < 0.0)
03426 {
03427 duration = 1.5;
03428 }
03429
03430 appCore->showText(s, horig, vorig, hoff, voff, duration);
03431
03432 return 0;
03433 }
03434
03435 static int celestia_gettextwidth(lua_State* l)
03436 {
03437 checkArgs(l, 2, 2, "One argument expected to function celestia:gettextwidth");
03438
03439 CelestiaCore* appCore = this_celestia(l);
03440 const char* s = safeGetString(l, 2, AllErrors, "First argument to celestia:gettextwidth must be a string");
03441
03442 lua_pushnumber(l, appCore->getTextWidth(s));
03443
03444 return 1;
03445 }
03446
03447 static int celestia_show(lua_State* l)
03448 {
03449 checkArgs(l, 1, 1000, "Wrong number of arguments to celestia:show");
03450 CelestiaCore* appCore = this_celestia(l);
03451
03452 int argc = lua_gettop(l);
03453 int flags = 0;
03454 for (int i = 2; i <= argc; i++)
03455 {
03456 string renderFlag = safeGetString(l, i, AllErrors, "Arguments to celestia:show() must be strings");
03457 if (renderFlag == "lightdelay")
03458 appCore->setLightDelayActive(true);
03459 else
03460 if (RenderFlagMap.count(renderFlag) > 0)
03461 flags |= RenderFlagMap[renderFlag];
03462 }
03463
03464 Renderer* r = appCore->getRenderer();
03465 r->setRenderFlags(r->getRenderFlags() | flags);
03466 appCore->notifyWatchers(CelestiaCore::RenderFlagsChanged);
03467
03468 return 0;
03469 }
03470
03471 static int celestia_hide(lua_State* l)
03472 {
03473 checkArgs(l, 1, 1000, "Wrong number of arguments to celestia:hide");
03474 CelestiaCore* appCore = this_celestia(l);
03475
03476 int argc = lua_gettop(l);
03477 int flags = 0;
03478 for (int i = 2; i <= argc; i++)
03479 {
03480 string renderFlag = safeGetString(l, i, AllErrors, "Arguments to celestia:hide() must be strings");
03481 if (renderFlag == "lightdelay")
03482 appCore->setLightDelayActive(false);
03483 else
03484 if (RenderFlagMap.count(renderFlag) > 0)
03485 flags |= RenderFlagMap[renderFlag];
03486 }
03487
03488 Renderer* r = appCore->getRenderer();
03489 r->setRenderFlags(r->getRenderFlags() & ~flags);
03490 appCore->notifyWatchers(CelestiaCore::RenderFlagsChanged);
03491
03492 return 0;
03493 }
03494
03495 static int celestia_setrenderflags(lua_State* l)
03496 {
03497 checkArgs(l, 2, 2, "One argument expected for celestia:setrenderflags()");
03498 CelestiaCore* appCore = this_celestia(l);
03499 if (!lua_istable(l, 2))
03500 {
03501 doError(l, "Argument to celestia:setrenderflags() must be a table");
03502 }
03503
03504 int renderFlags = appCore->getRenderer()->getRenderFlags();
03505 lua_pushnil(l);
03506 while (lua_next(l, -2) != 0)
03507 {
03508 string key;
03509 bool value = false;
03510 if (lua_isstring(l, -2))
03511 {
03512 key = lua_tostring(l, -2);
03513 }
03514 else
03515 {
03516 doError(l, "Keys in table-argument to celestia:setrenderflags() must be strings");
03517 }
03518 if (lua_isboolean(l, -1))
03519 {
03520 value = lua_toboolean(l, -1);
03521 }
03522 else
03523 {
03524 doError(l, "Values in table-argument to celestia:setrenderflags() must be boolean");
03525 }
03526 if (key == "lightdelay")
03527 {
03528 appCore->setLightDelayActive(value);
03529 }
03530 else if (RenderFlagMap.count(key) > 0)
03531 {
03532 int flag = RenderFlagMap[key];
03533 if (value)
03534 {
03535 renderFlags |= flag;
03536 }
03537 else
03538 {
03539 renderFlags &= ~flag;
03540 }
03541 }
03542 else
03543 {
03544 cerr << "Unknown key: " << key << "\n";
03545 }
03546 lua_pop(l,1);
03547 }
03548 appCore->getRenderer()->setRenderFlags(renderFlags);
03549 appCore->notifyWatchers(CelestiaCore::RenderFlagsChanged);
03550
03551 return 0;
03552 }
03553
03554 static int celestia_getrenderflags(lua_State* l)
03555 {
03556 checkArgs(l, 1, 1, "No arguments expected for celestia:getrenderflags()");
03557 CelestiaCore* appCore = this_celestia(l);
03558 lua_newtable(l);
03559 FlagMap::const_iterator it = RenderFlagMap.begin();
03560 const int renderFlags = appCore->getRenderer()->getRenderFlags();
03561 while (it != RenderFlagMap.end())
03562 {
03563 string key = it->first;
03564 lua_pushstring(l, key.c_str());
03565 lua_pushboolean(l, (it->second & renderFlags) != 0);
03566 lua_settable(l,-3);
03567 it++;
03568 }
03569 lua_pushstring(l, "lightdelay");
03570 lua_pushboolean(l, appCore->getLightDelayActive());
03571 lua_settable(l, -3);
03572 return 1;
03573 }
03574
03575 int celestia_getscreendimension(lua_State* l)
03576 {
03577 checkArgs(l, 1, 1, "No arguments expected for celestia:getscreendimension()");
03578
03579 this_celestia(l);
03580
03581 int viewport[4];
03582 glGetIntegerv(GL_VIEWPORT, viewport);
03583 lua_pushnumber(l, viewport[2]-viewport[0]);
03584 lua_pushnumber(l, viewport[3]-viewport[1]);
03585 return 2;
03586 }
03587
03588 static int celestia_showlabel(lua_State* l)
03589 {
03590 checkArgs(l, 1, 1000, "Bad method call!");
03591 CelestiaCore* appCore = this_celestia(l);
03592
03593 int argc = lua_gettop(l);
03594 int flags = 0;
03595 for (int i = 2; i <= argc; i++)
03596 {
03597 string labelFlag = safeGetString(l, i, AllErrors, "Arguments to celestia:showlabel() must be strings");
03598 if (LabelFlagMap.count(labelFlag) > 0)
03599 flags |= LabelFlagMap[labelFlag];
03600 }
03601
03602 Renderer* r = appCore->getRenderer();
03603 r->setLabelMode(r->getLabelMode() | flags);
03604 appCore->notifyWatchers(CelestiaCore::LabelFlagsChanged);
03605
03606 return 0;
03607 }
03608
03609 static int celestia_hidelabel(lua_State* l)
03610 {
03611 checkArgs(l, 1, 1000, "Invalid number of arguments in celestia:hidelabel");
03612 CelestiaCore* appCore = this_celestia(l);
03613
03614 int argc = lua_gettop(l);
03615 int flags = 0;
03616 for (int i = 2; i <= argc; i++)
03617 {
03618 string labelFlag = safeGetString(l, i, AllErrors, "Arguments to celestia:hidelabel() must be strings");
03619 if (LabelFlagMap.count(labelFlag) > 0)
03620 flags |= LabelFlagMap[labelFlag];
03621 }
03622
03623 Renderer* r = appCore->getRenderer();
03624 r->setLabelMode(r->getLabelMode() & ~flags);
03625 appCore->notifyWatchers(CelestiaCore::LabelFlagsChanged);
03626
03627 return 0;
03628 }
03629
03630 static int celestia_setlabelflags(lua_State* l)
03631 {
03632 checkArgs(l, 2, 2, "One argument expected for celestia:setlabelflags()");
03633 CelestiaCore* appCore = this_celestia(l);
03634 if (!lua_istable(l, 2))
03635 {
03636 doError(l, "Argument to celestia:setlabelflags() must be a table");
03637 }
03638
03639 int labelFlags = appCore->getRenderer()->getLabelMode();
03640 lua_pushnil(l);
03641 while (lua_next(l, -2) != 0)
03642 {
03643 string key;
03644 bool value = false;
03645 if (lua_isstring(l, -2))
03646 {
03647 key = lua_tostring(l, -2);
03648 }
03649 else
03650 {
03651 doError(l, "Keys in table-argument to celestia:setlabelflags() must be strings");
03652 }
03653 if (lua_isboolean(l, -1))
03654 {
03655 value = lua_toboolean(l, -1);
03656 }
03657 else
03658 {
03659 doError(l, "Values in table-argument to celestia:setlabelflags() must be boolean");
03660 }
03661 if (LabelFlagMap.count(key) == 0)
03662 {
03663 cerr << "Unknown key: " << key << "\n";
03664 }
03665 else
03666 {
03667 int flag = LabelFlagMap[key];
03668 if (value)
03669 {
03670 labelFlags |= flag;
03671 }
03672 else
03673 {
03674 labelFlags &= ~flag;
03675 }
03676 }
03677 lua_pop(l,1);
03678 }
03679 appCore->getRenderer()->setLabelMode(labelFlags);
03680 appCore->notifyWatchers(CelestiaCore::LabelFlagsChanged);
03681
03682 return 0;
03683 }
03684
03685 static int celestia_getlabelflags(lua_State* l)
03686 {
03687 checkArgs(l, 1, 1, "No arguments expected for celestia:getlabelflags()");
03688 CelestiaCore* appCore = this_celestia(l);
03689 lua_newtable(l);
03690 FlagMap::const_iterator it = LabelFlagMap.begin();
03691 const int labelFlags = appCore->getRenderer()->getLabelMode();
03692 while (it != LabelFlagMap.end())
03693 {
03694 string key = it->first;
03695 lua_pushstring(l, key.c_str());
03696 lua_pushboolean(l, (it->second & labelFlags) != 0);
03697 lua_settable(l,-3);
03698 it++;
03699 }
03700 return 1;
03701 }
03702
03703 static int celestia_setorbitflags(lua_State* l)
03704 {
03705 checkArgs(l, 2, 2, "One argument expected for celestia:setorbitflags()");
03706 CelestiaCore* appCore = this_celestia(l);
03707 if (!lua_istable(l, 2))
03708 {
03709 doError(l, "Argument to celestia:setorbitflags() must be a table");
03710 }
03711
03712 int orbitFlags = appCore->getRenderer()->getOrbitMask();
03713 lua_pushnil(l);
03714 while (lua_next(l, -2) != 0)
03715 {
03716 string key;
03717 bool value = false;
03718 if (lua_isstring(l, -2))
03719 {
03720 key = lua_tostring(l, -2);
03721 }
03722 else
03723 {
03724 doError(l, "Keys in table-argument to celestia:setorbitflags() must be strings");
03725 }
03726 if (lua_isboolean(l, -1))
03727 {
03728 value = lua_toboolean(l, -1);
03729 }
03730 else
03731 {
03732 doError(l, "Values in table-argument to celestia:setorbitflags() must be boolean");
03733 }
03734 if (BodyTypeMap.count(key) == 0)
03735 {
03736 cerr << "Unknown key: " << key << "\n";
03737 }
03738 else
03739 {
03740 int flag = BodyTypeMap[key];
03741 if (value)
03742 {
03743 orbitFlags |= flag;
03744 }
03745 else
03746 {
03747 orbitFlags &= ~flag;
03748 }
03749 }
03750 lua_pop(l,1);
03751 }
03752 appCore->getRenderer()->setOrbitMask(orbitFlags);
03753 return 0;
03754 }
03755
03756 static int celestia_getorbitflags(lua_State* l)
03757 {
03758 checkArgs(l, 1, 1, "No arguments expected for celestia:getorbitflags()");
03759 CelestiaCore* appCore = this_celestia(l);
03760 lua_newtable(l);
03761 FlagMap::const_iterator it = BodyTypeMap.begin();
03762 const int orbitFlags = appCore->getRenderer()->getOrbitMask();
03763 while (it != BodyTypeMap.end())
03764 {
03765 string key = it->first;
03766 lua_pushstring(l, key.c_str());
03767 lua_pushboolean(l, (it->second & orbitFlags) != 0);
03768 lua_settable(l,-3);
03769 it++;
03770 }
03771 return 1;
03772 }
03773
03774 static int celestia_setfaintestvisible(lua_State* l)
03775 {
03776 checkArgs(l, 2, 2, "One argument expected for celestia:setfaintestvisible()");
03777 CelestiaCore* appCore = this_celestia(l);
03778 float faintest = (float)safeGetNumber(l, 2, AllErrors, "Argument to celestia:setfaintestvisible() must be a number");
03779 if ((appCore->getRenderer()->getRenderFlags() & Renderer::ShowAutoMag) == 0)
03780 {
03781 faintest = min(15.0f, max(1.0f, faintest));
03782 appCore->setFaintest(faintest);
03783 appCore->notifyWatchers(CelestiaCore::FaintestChanged);
03784 }
03785 else
03786 {
03787 faintest = min(12.0f, max(6.0f, faintest));
03788 appCore->getRenderer()->setFaintestAM45deg(faintest);
03789 appCore->setFaintestAutoMag();
03790 }
03791 return 0;
03792 }
03793
03794 static int celestia_getfaintestvisible(lua_State* l)
03795 {
03796 checkArgs(l, 1, 1, "No arguments expected for celestia:getfaintestvisible()");
03797 CelestiaCore* appCore = this_celestia(l);
03798 if ((appCore->getRenderer()->getRenderFlags() & Renderer::ShowAutoMag) == 0)
03799 {
03800 lua_pushnumber(l, appCore->getSimulation()->getFaintestVisible());
03801 }
03802 else
03803 {
03804 lua_pushnumber(l, appCore->getRenderer()->getFaintestAM45deg());
03805 }
03806 return 1;
03807 }
03808
03809 static int celestia_setminfeaturesize(lua_State* l)
03810 {
03811 checkArgs(l, 2, 2, "One argument expected for celestia:setminfeaturesize()");
03812 CelestiaCore* appCore = this_celestia(l);
03813 float minFeatureSize = (float)safeGetNumber(l, 2, AllErrors, "Argument to celestia:setminfeaturesize() must be a number");
03814 minFeatureSize = max(0.0f, minFeatureSize);
03815 appCore->getRenderer()->setMinimumFeatureSize(minFeatureSize);
03816 return 0;
03817 }
03818
03819 static int celestia_getminfeaturesize(lua_State* l)
03820 {
03821 checkArgs(l, 1, 1, "No arguments expected for celestia:getminfeaturesize()");
03822 CelestiaCore* appCore = this_celestia(l);
03823 lua_pushnumber(l, appCore->getRenderer()->getMinimumFeatureSize());
03824 return 1;
03825 }
03826
03827 static int celestia_getobserver(lua_State* l)
03828 {
03829 checkArgs(l, 1, 1, "No arguments expected for celestia:getobserver()");
03830
03831 CelestiaCore* appCore = this_celestia(l);
03832 Observer* o = appCore->getSimulation()->getActiveObserver();
03833 if (o == NULL)
03834 lua_pushnil(l);
03835 else
03836 observer_new(l, o);
03837
03838 return 1;
03839 }
03840
03841 static int celestia_getobservers(lua_State* l)
03842 {
03843 checkArgs(l, 1, 1, "No arguments expected for celestia:getobservers()");
03844 CelestiaCore* appCore = this_celestia(l);
03845
03846 vector<Observer*> observer_list;
03847 getObservers(appCore, observer_list);
03848 lua_newtable(l);
03849 for (unsigned int i = 0; i < observer_list.size(); i++)
03850 {
03851 observer_new(l, observer_list[i]);
03852 lua_rawseti(l, -2, i + 1);
03853 }
03854
03855 return 1;
03856 }
03857
03858 static int celestia_getselection(lua_State* l)
03859 {
03860 checkArgs(l, 1, 1, "No arguments expected to celestia:getselection()");
03861 CelestiaCore* appCore = this_celestia(l);
03862 Selection sel = appCore->getSimulation()->getSelection();
03863 object_new(l, sel);
03864
03865 return 1;
03866 }
03867
03868 static int celestia_find(lua_State* l)
03869 {
03870 checkArgs(l, 2, 2, "One argument expected for function celestia:find()");
03871 if (!lua_isstring(l, 2))
03872 {
03873 doError(l, "Argument to find must be a string");
03874 }
03875
03876 CelestiaCore* appCore = this_celestia(l);
03877 Simulation* sim = appCore->getSimulation();
03878
03879 Selection sel = sim->findObjectFromPath(lua_tostring(l, 2));
03880 object_new(l, sel);
03881
03882 return 1;
03883 }
03884
03885 static int celestia_select(lua_State* l)
03886 {
03887 checkArgs(l, 2, 2, "One argument expected for celestia:select()");
03888 CelestiaCore* appCore = this_celestia(l);
03889
03890 Simulation* sim = appCore->getSimulation();
03891 Selection* sel = to_object(l, 2);
03892
03893
03894
03895 if (sel != NULL)
03896 sim->setSelection(*sel);
03897 else
03898 sim->setSelection(Selection());
03899
03900 return 0;
03901 }
03902
03903 static int celestia_mark(lua_State* l)
03904 {
03905 checkArgs(l, 2, 2, "One argument expected to function celestia:mark");
03906
03907 CelestiaCore* appCore = this_celestia(l);
03908 Simulation* sim = appCore->getSimulation();
03909 Selection* sel = to_object(l, 2);
03910
03911 if (sel != NULL)
03912 {
03913 sim->getUniverse()->markObject(*sel, 10.0f,
03914 Color(0.0f, 1.0f, 0.0f), Marker::Diamond, 1);
03915 }
03916 else
03917 {
03918 doError(l, "Argument to celestia:mark must be an object");
03919 }
03920
03921 return 0;
03922 }
03923
03924 static int celestia_unmark(lua_State* l)
03925 {
03926 checkArgs(l, 2, 2, "One argument expected to function celestia:unmark");
03927
03928 CelestiaCore* appCore = this_celestia(l);
03929 Simulation* sim = appCore->getSimulation();
03930 Selection* sel = to_object(l, 2);
03931
03932 if (sel != NULL)
03933 {
03934 sim->getUniverse()->unmarkObject(*sel, 1);
03935 }
03936 else
03937 {
03938 doError(l, "Argument to celestia:unmark must be an object");
03939 }
03940
03941 return 0;
03942 }
03943
03944 static int celestia_gettime(lua_State* l)
03945 {
03946 checkArgs(l, 1, 1, "No argument expected to function celestia:gettime");
03947
03948 CelestiaCore* appCore = this_celestia(l);
03949 Simulation* sim = appCore->getSimulation();
03950 lua_pushnumber(l, sim->getTime());
03951
03952 return 1;
03953 }
03954
03955 static int celestia_gettimescale(lua_State* l)
03956 {
03957 checkArgs(l, 1, 1, "No argument expected to function celestia:gettimescale");
03958
03959 CelestiaCore* appCore = this_celestia(l);
03960 lua_pushnumber(l, appCore->getSimulation()->getTimeScale());
03961
03962 return 1;
03963 }
03964
03965 static int celestia_settime(lua_State* l)
03966 {
03967 checkArgs(l, 2, 2, "One argument expected to function celestia:settime");
03968
03969 CelestiaCore* appCore = this_celestia(l);
03970 double t = safeGetNumber(l, 2, AllErrors, "Second arg to celestia:settime must be a number");
03971 appCore->getSimulation()->setTime(t);
03972
03973 return 0;
03974 }
03975
03976 static int celestia_settimescale(lua_State* l)
03977 {
03978 checkArgs(l, 2, 2, "One argument expected to function celestia:settimescale");
03979
03980 CelestiaCore* appCore = this_celestia(l);
03981 double t = safeGetNumber(l, 2, AllErrors, "Second arg to celestia:settimescale must be a number");
03982 appCore->getSimulation()->setTimeScale(t);
03983
03984 return 0;
03985 }
03986
03987 static int celestia_tojulianday(lua_State* l)
03988 {
03989 checkArgs(l, 2, 7, "Wrong number of arguments to function celestia:tojulianday");
03990
03991
03992 this_celestia(l);
03993
03994 int year = (int)safeGetNumber(l, 2, AllErrors, "First arg to celestia:tojulianday must be a number", 0.0);
03995 int month = (int)safeGetNumber(l, 3, WrongType, "Second arg to celestia:tojulianday must be a number", 1.0);
03996 int day = (int)safeGetNumber(l, 4, WrongType, "Third arg to celestia:tojulianday must be a number", 1.0);
03997 int hour = (int)safeGetNumber(l, 5, WrongType, "Fourth arg to celestia:tojulianday must be a number", 0.0);
03998 int minute = (int)safeGetNumber(l, 6, WrongType, "Fifth arg to celestia:tojulianday must be a number", 0.0);
03999 double seconds = safeGetNumber(l, 7, WrongType, "Sixth arg to celestia:tojulianday must be a number", 0.0);
04000
04001 astro::Date date(year, month, day);
04002 date.hour = hour;
04003 date.minute = minute;
04004 date.seconds = seconds;
04005
04006 double jd = (double) date;
04007
04008 lua_pushnumber(l, jd);
04009
04010 return 1;
04011 }
04012
04013 static int celestia_fromjulianday(lua_State* l)
04014 {
04015 checkArgs(l, 2, 2, "Wrong number of arguments to function celestia:fromjulianday");
04016
04017
04018 this_celestia(l);
04019
04020 double jd = safeGetNumber(l, 2, AllErrors, "First arg to celestia:fromjulianday must be a number", 0.0);
04021 astro::Date date(jd);
04022
04023 lua_newtable(l);
04024 setTable(l, "year", (double)date.year);
04025 setTable(l, "month", (double)date.month);
04026 setTable(l, "day", (double)date.day);
04027 setTable(l, "hour", (double)date.hour);
04028 setTable(l, "minute", (double)date.minute);
04029 setTable(l, "seconds", date.seconds);
04030
04031 return 1;
04032 }
04033
04034 static int celestia_unmarkall(lua_State* l)
04035 {
04036 checkArgs(l, 1, 1, "No arguments expected to function celestia:unmarkall");
04037
04038 CelestiaCore* appCore = this_celestia(l);
04039 Simulation* sim = appCore->getSimulation();
04040 sim->getUniverse()->unmarkAll();
04041
04042 return 0;
04043 }
04044
04045 static int celestia_getstarcount(lua_State* l)
04046 {
04047 checkArgs(l, 1, 1, "No arguments expected to function celestia:getstarcount");
04048
04049 CelestiaCore* appCore = this_celestia(l);
04050 Universe* u = appCore->getSimulation()->getUniverse();
04051 lua_pushnumber(l, u->getStarCatalog()->size());
04052
04053 return 1;
04054 }
04055
04056 static int celestia_setambient(lua_State* l)
04057 {
04058 checkArgs(l, 2, 2, "One argument expected in celestia:setambient");
04059 CelestiaCore* appCore = this_celestia(l);
04060
04061 Renderer* renderer = appCore->getRenderer();
04062 double ambientLightLevel = safeGetNumber(l, 2, AllErrors, "Argument to celestia:setambient must be a number");
04063 if (ambientLightLevel > 1.0)
04064 ambientLightLevel = 1.0;
04065 if (ambientLightLevel < 0.0)
04066 ambientLightLevel = 0.0;
04067
04068 if (renderer != NULL)
04069 renderer->setAmbientLightLevel((float)ambientLightLevel);
04070 appCore->notifyWatchers(CelestiaCore::AmbientLightChanged);
04071
04072 return 0;
04073 }
04074
04075 static int celestia_getambient(lua_State* l)
04076 {
04077 checkArgs(l, 1, 1, "No argument expected in celestia:setambient");
04078 CelestiaCore* appCore = this_celestia(l);
04079
04080 Renderer* renderer = appCore->getRenderer();
04081 if (renderer == NULL)
04082 {
04083 doError(l, "Internal Error: renderer is NULL!");
04084 }
04085 else
04086 {
04087 lua_pushnumber(l, renderer->getAmbientLightLevel());
04088 }
04089 return 1;
04090 }
04091
04092 static int celestia_setminorbitsize(lua_State* l)
04093 {
04094 checkArgs(l, 2, 2, "One argument expected in celestia:setminorbitsize");
04095 CelestiaCore* appCore = this_celestia(l);
04096
04097 double orbitSize = safeGetNumber(l, 2, AllErrors, "Argument to celestia:setminorbitsize() must be a number");
04098 Renderer* renderer = appCore->getRenderer();
04099 if (renderer == NULL)
04100 {
04101 doError(l, "Internal Error: renderer is NULL!");
04102 }
04103 else
04104 {
04105 orbitSize = max(0.0, orbitSize);
04106 renderer->setMinimumOrbitSize((float)orbitSize);
04107 }
04108 return 0;
04109 }
04110
04111 static int celestia_getminorbitsize(lua_State* l)
04112 {
04113 checkArgs(l, 1, 1, "No argument expected in celestia:getminorbitsize");
04114 CelestiaCore* appCore = this_celestia(l);
04115
04116 Renderer* renderer = appCore->getRenderer();
04117 if (renderer == NULL)
04118 {
04119 doError(l, "Internal Error: renderer is NULL!");
04120 }
04121 else
04122 {
04123 lua_pushnumber(l, renderer->getMinimumOrbitSize());
04124 }
04125 return 1;
04126 }
04127
04128 static int celestia_setstardistancelimit(lua_State* l)
04129 {
04130 checkArgs(l, 2, 2, "One argument expected in celestia:setstardistancelimit");
04131 CelestiaCore* appCore = this_celestia(l);
04132
04133 double distanceLimit = safeGetNumber(l, 2, AllErrors, "Argument to celestia:setstardistancelimit() must be a number");
04134 Renderer* renderer = appCore->getRenderer();
04135 if (renderer == NULL)
04136 {
04137 doError(l, "Internal Error: renderer is NULL!");
04138 }
04139 else
04140 {
04141 renderer->setDistanceLimit((float)distanceLimit);
04142 }
04143 return 0;
04144 }
04145
04146 static int celestia_getstardistancelimit(lua_State* l)
04147 {
04148 checkArgs(l, 1, 1, "No argument expected in celestia:getstardistancelimit");
04149 CelestiaCore* appCore = this_celestia(l);
04150
04151 Renderer* renderer = appCore->getRenderer();
04152 if (renderer == NULL)
04153 {
04154 doError(l, "Internal Error: renderer is NULL!");
04155 }
04156 else
04157 {
04158 lua_pushnumber(l, renderer->getDistanceLimit());
04159 }
04160 return 1;
04161 }
04162
04163 static int celestia_getstarstyle(lua_State* l)
04164 {
04165 checkArgs(l, 1, 1, "No argument expected in celestia:getstarstyle");
04166 CelestiaCore* appCore = this_celestia(l);
04167
04168 Renderer* renderer = appCore->getRenderer();
04169 if (renderer == NULL)
04170 {
04171 doError(l, "Internal Error: renderer is NULL!");
04172 }
04173 else
04174 {
04175 Renderer::StarStyle starStyle = renderer->getStarStyle();
04176 switch (starStyle)
04177 {
04178 case Renderer::FuzzyPointStars:
04179 lua_pushstring(l, "fuzzy"); break;
04180 case Renderer::PointStars:
04181 lua_pushstring(l, "point"); break;
04182 case Renderer::ScaledDiscStars:
04183 lua_pushstring(l, "disc"); break;
04184 default:
04185 lua_pushstring(l, "invalid starstyle");
04186 };
04187 }
04188 return 1;
04189 }
04190
04191 static int celestia_setstarstyle(lua_State* l)
04192 {
04193 checkArgs(l, 2, 2, "One argument expected in celestia:setstarstyle");
04194 CelestiaCore* appCore = this_celestia(l);
04195
04196 string starStyle = safeGetString(l, 2, AllErrors, "Argument to celestia:setstarstyle must be a string");
04197 Renderer* renderer = appCore->getRenderer();
04198 if (renderer == NULL)
04199 {
04200 doError(l, "Internal Error: renderer is NULL!");
04201 }
04202 else
04203 {
04204 if (starStyle == "fuzzy")
04205 {
04206 renderer->setStarStyle(Renderer::FuzzyPointStars);
04207 }
04208 else if (starStyle == "point")
04209 {
04210 renderer->setStarStyle(Renderer::PointStars);
04211 }
04212 else if (starStyle == "disc")
04213 {
04214 renderer->setStarStyle(Renderer::ScaledDiscStars);
04215 }
04216 else
04217 {
04218 doError(l, "Invalid starstyle");
04219 }
04220 appCore->notifyWatchers(CelestiaCore::RenderFlagsChanged);
04221
04222 }
04223 return 0;
04224 }
04225
04226 static int celestia_getstar(lua_State* l)
04227 {
04228 checkArgs(l, 2, 2, "One argument expected to function celestia:getstar");
04229
04230 CelestiaCore* appCore = this_celestia(l);
04231 double starIndex = safeGetNumber(l, 2, AllErrors, "First arg to celestia:getstar must be a number");
04232 Universe* u = appCore->getSimulation()->getUniverse();
04233 Star* star = u->getStarCatalog()->getStar((uint32) starIndex);
04234 if (star == NULL)
04235 lua_pushnil(l);
04236 else
04237 object_new(l, Selection(star));
04238
04239 return 1;
04240 }
04241
04242 static int celestia_newvector(lua_State* l)
04243 {
04244 checkArgs(l, 4, 4, "Expected 3 arguments for celestia:newvector");
04245
04246 this_celestia(l);
04247 double x = safeGetNumber(l, 2, AllErrors, "First arg to celestia:newvector must be a number");
04248 double y = safeGetNumber(l, 3, AllErrors, "Second arg to celestia:newvector must be a number");
04249 double z = safeGetNumber(l, 4, AllErrors, "Third arg to celestia:newvector must be a number");
04250
04251 vector_new(l, Vec3d(x,y,z));
04252
04253 return 1;
04254 }
04255
04256 static int celestia_newposition(lua_State* l)
04257 {
04258 checkArgs(l, 4, 4, "Expected 3 arguments for celestia:newposition");
04259
04260 this_celestia(l);
04261 BigFix components[3];
04262 for (int i = 0; i < 3; i++)
04263 {
04264 if (lua_isnumber(l, i+2))
04265 {
04266 double v = lua_tonumber(l, i+2);
04267 components[i] = BigFix(v);
04268 }
04269 else if (lua_isstring(l, i+2))
04270 {
04271 components[i] = BigFix(string(lua_tostring(l, i+2)));
04272 }
04273 else
04274 {
04275 doError(l, "Arguments to celestia:newposition must be either numbers or strings");
04276 }
04277 }
04278
04279 position_new(l, UniversalCoord(components[0], components[1], components[2]));
04280
04281 return 1;
04282 }
04283
04284 static int celestia_newrotation(lua_State* l)
04285 {
04286 checkArgs(l, 3, 5, "Need 2 or 4 arguments for celestia:newrotation");
04287
04288 this_celestia(l);
04289
04290 if (lua_gettop(l) > 3)
04291 {
04292
04293 double w = safeGetNumber(l, 2, AllErrors, "arguments to celestia:newrotation must either be (vec, number) or four numbers");
04294 double x = safeGetNumber(l, 3, AllErrors, "arguments to celestia:newrotation must either be (vec, number) or four numbers");
04295 double y = safeGetNumber(l, 4, AllErrors, "arguments to celestia:newrotation must either be (vec, number) or four numbers");
04296 double z = safeGetNumber(l, 5, AllErrors, "arguments to celestia:newrotation must either be (vec, number) or four numbers");
04297 Quatd q(w, x, y, z);
04298 rotation_new(l, q);
04299 }
04300 else
04301 {
04302 Vec3d* v = to_vector(l, 2);
04303 if (v == NULL)
04304 {
04305 doError(l, "newrotation: first argument must be a vector");
04306 }
04307 double angle = safeGetNumber(l, 3, AllErrors, "second argument to celestia:newrotation must be a number");
04308 Quatd q;
04309 q.setAxisAngle(*v, angle);
04310 rotation_new(l, q);
04311 }
04312 return 1;
04313 }
04314
04315 static int celestia_getscripttime(lua_State* l)
04316 {
04317 checkArgs(l, 1, 1, "No arguments expected for celestia:getscripttime");
04318
04319 this_celestia(l);
04320
04321 LuaState* luastate_ptr = getLuaStateObject(l);
04322 lua_pushnumber(l, luastate_ptr->getTime());
04323 return 1;
04324 }
04325
04326 static int celestia_newframe(lua_State* l)
04327 {
04328 checkArgs(l, 2, 4, "One to three arguments expected for function celestia:newframe");
04329 int argc = lua_gettop(l);
04330
04331
04332 this_celestia(l);
04333
04334 const char* coordsysName = safeGetString(l, 2, AllErrors, "newframe: first argument must be a string");
04335 astro::CoordinateSystem coordSys = parseCoordSys(coordsysName);
04336 Selection* ref = NULL;
04337 Selection* target = NULL;
04338
04339 if (coordSys == astro::Universal)
04340 {
04341 frame_new(l, FrameOfReference());
04342 }
04343 else if (coordSys == astro::PhaseLock)
04344 {
04345 if (argc >= 4)
04346 {
04347 ref = to_object(l, 3);
04348 target = to_object(l, 4);
04349 }
04350
04351 if (ref == NULL || target == NULL)
04352 {
04353 doError(l, "newframe: two objects required for lock frame");
04354 }
04355
04356 frame_new(l, FrameOfReference(coordSys, *ref, *target));
04357 }
04358 else
04359 {
04360 if (argc >= 3)
04361 ref = to_object(l, 3);
04362 if (ref == NULL)
04363 {
04364 doError(l, "newframe: one object argument required for frame");
04365 }
04366
04367 frame_new(l, FrameOfReference(coordSys, *ref));
04368 }
04369
04370 return 1;
04371 }
04372
04373 static int celestia_requestkeyboard(lua_State* l)
04374 {
04375 checkArgs(l, 2, 2, "Need one arguments for celestia:requestkeyboard");
04376 CelestiaCore* appCore = this_celestia(l);
04377
04378 if (!lua_isboolean(l, 2))
04379 {
04380 doError(l, "First argument for celestia:requestkeyboard must be a boolean");
04381 }
04382
04383 int mode = appCore->getTextEnterMode();
04384
04385 if (lua_toboolean(l, 2))
04386 {
04387
04388 lua_pushstring(l, KbdCallback);
04389 lua_gettable(l, LUA_GLOBALSINDEX);
04390 if (lua_isnil(l, -1))
04391 {
04392 doError(l, "script requested keyboard, but did not provide callback");
04393 }
04394 lua_remove(l, -1);
04395
04396 mode = mode | CelestiaCore::KbPassToScript;
04397 }
04398 else
04399 {
04400 mode = mode & ~CelestiaCore::KbPassToScript;
04401 }
04402 appCore->setTextEnterMode(mode);
04403
04404 return 0;
04405 }
04406
04407 static int celestia_takescreenshot(lua_State* l)
04408 {
04409 checkArgs(l, 1, 3, "Need 0 to 2 arguments for celestia:takescreenshot");
04410 CelestiaCore* appCore = this_celestia(l);
04411 LuaState* luastate = getLuaStateObject(l);
04412
04413 double timeToTimeout = luastate->timeout - luastate->getTime();
04414
04415 const char* filetype = safeGetString(l, 2, WrongType, "First argument to celestia:takescreenshot must be a string");
04416 if (filetype == NULL)
04417 filetype = "png";
04418
04419
04420 const char* fileid_ptr = safeGetString(l, 3, WrongType, "Second argument to celestia:takescreenshot must be a string");
04421 if (fileid_ptr == NULL)
04422 fileid_ptr = "";
04423 string fileid(fileid_ptr);
04424
04425
04426 for (unsigned int i = 0; i < fileid.length(); i++)
04427 {
04428 char ch = fileid[i];
04429 if (!((ch >= 'a' && ch <= 'z') ||
04430 (fileid[i] >= 'A' && ch <= 'Z') ||
04431 (ch >= '0' && ch <= '9') ) )
04432 fileid[i] = '_';
04433 }
04434
04435 if (fileid.length() > 16)
04436 fileid = fileid.substr(0, 16);
04437 if (fileid.length() > 0)
04438 fileid.append("-");
04439
04440 string path = appCore->getConfig()->scriptScreenshotDirectory;
04441 if (path.length() > 0 &&
04442 path[path.length()-1] != '/' &&
04443 path[path.length()-1] != '\\')
04444
04445 path.append("/");
04446
04447 luastate->screenshotCount++;
04448 bool success = false;
04449 char filenamestem[48];
04450 sprintf(filenamestem, "screenshot-%s%06i", fileid.c_str(), luastate->screenshotCount);
04451
04452
04453 int viewport[4];
04454 glGetIntegerv(GL_VIEWPORT, viewport);
04455
04456 #ifndef MACOSX
04457 if (strncmp(filetype, "jpg", 3) == 0)
04458 {
04459 string filepath = path + filenamestem + ".jpg";
04460 success = CaptureGLBufferToJPEG(string(filepath),
04461 viewport[0], viewport[1],
04462 viewport[2], viewport[3]);
04463 }
04464 else
04465 {
04466 string filepath = path + filenamestem + ".png";
04467 success = CaptureGLBufferToPNG(string(filepath),
04468 viewport[0], viewport[1],
04469 viewport[2], viewport[3]);
04470 }
04471 #endif
04472 lua_pushboolean(l, success);
04473
04474
04475 luastate->timeout = luastate->getTime() + timeToTimeout - 0.1;
04476 return 1;
04477 }
04478
04479 static int celestia_createcelscript(lua_State* l)
04480 {
04481 checkArgs(l, 2, 2, "Need one argument for celestia:createcelscript()");
04482 string scripttext = safeGetString(l, 2, AllErrors, "Argument to celestia:createcelscript() must be a string");
04483 return celscript_from_string(l, scripttext);
04484 }
04485
04486 static int celestia_requestsystemaccess(lua_State* l)
04487 {
04488
04489 checkArgs(l, 1, 2, "No argument expected for celestia:requestsystemaccess()");
04490 this_celestia(l);
04491 LuaState* luastate = getLuaStateObject(l);
04492 luastate->requestIO();
04493 return 0;
04494 }
04495
04496 static int celestia_getscriptpath(lua_State* l)
04497 {
04498
04499 checkArgs(l, 1, 1, "No argument expected for celestia:requestsystemaccess()");
04500 this_celestia(l);
04501 lua_pushstring(l, "celestia-scriptpath");
04502 lua_gettable(l, LUA_REGISTRYINDEX);
04503 return 1;
04504 }
04505
04506 static int celestia_tostring(lua_State* l)
04507 {
04508 lua_pushstring(l, "[Celestia]");
04509
04510 return 1;
04511 }
04512
04513 static void CreateCelestiaMetaTable(lua_State* l)
04514 {
04515 CreateClassMetatable(l, _Celestia);
04516
04517 RegisterMethod(l, "__tostring", celestia_tostring);
04518 RegisterMethod(l, "flash", celestia_flash);
04519 RegisterMethod(l, "print", celestia_print);
04520 RegisterMethod(l, "gettextwidth", celestia_gettextwidth);
04521 RegisterMethod(l, "show", celestia_show);
04522 RegisterMethod(l, "hide", celestia_hide);
04523 RegisterMethod(l, "getrenderflags", celestia_getrenderflags);
04524 RegisterMethod(l, "setrenderflags", celestia_setrenderflags);
04525 RegisterMethod(l, "getscreendimension", celestia_getscreendimension);
04526 RegisterMethod(l, "showlabel", celestia_showlabel);
04527 RegisterMethod(l, "hidelabel", celestia_hidelabel);
04528 RegisterMethod(l, "getlabelflags", celestia_getlabelflags);
04529 RegisterMethod(l, "setlabelflags", celestia_setlabelflags);
04530 RegisterMethod(l, "getorbitflags", celestia_getorbitflags);
04531 RegisterMethod(l, "setorbitflags", celestia_setorbitflags);
04532 RegisterMethod(l, "getfaintestvisible", celestia_getfaintestvisible);
04533 RegisterMethod(l, "setfaintestvisible", celestia_setfaintestvisible);
04534 RegisterMethod(l, "setminfeaturesize", celestia_setminfeaturesize);
04535 RegisterMethod(l, "getminfeaturesize", celestia_getminfeaturesize);
04536 RegisterMethod(l, "getobserver", celestia_getobserver);
04537 RegisterMethod(l, "getobservers", celestia_getobservers);
04538 RegisterMethod(l, "getselection", celestia_getselection);
04539 RegisterMethod(l, "find", celestia_find);
04540 RegisterMethod(l, "select", celestia_select);
04541 RegisterMethod(l, "mark", celestia_mark);
04542 RegisterMethod(l, "unmark", celestia_unmark);
04543 RegisterMethod(l, "unmarkall", celestia_unmarkall);
04544 RegisterMethod(l, "gettime", celestia_gettime);
04545 RegisterMethod(l, "settime", celestia_settime);
04546 RegisterMethod(l, "gettimescale", celestia_gettimescale);
04547 RegisterMethod(l, "settimescale", celestia_settimescale);
04548 RegisterMethod(l, "getambient", celestia_getambient);
04549 RegisterMethod(l, "setambient", celestia_setambient);
04550 RegisterMethod(l, "getminorbitsize", celestia_getminorbitsize);
04551 RegisterMethod(l, "setminorbitsize", celestia_setminorbitsize);
04552 RegisterMethod(l, "getstardistancelimit", celestia_getstardistancelimit);
04553 RegisterMethod(l, "setstardistancelimit", celestia_setstardistancelimit);
04554 RegisterMethod(l, "getstarstyle", celestia_getstarstyle);
04555 RegisterMethod(l, "setstarstyle", celestia_setstarstyle);
04556 RegisterMethod(l, "tojulianday", celestia_tojulianday);
04557 RegisterMethod(l, "fromjulianday", celestia_fromjulianday);
04558 RegisterMethod(l, "getstarcount", celestia_getstarcount);
04559 RegisterMethod(l, "getstar", celestia_getstar);
04560 RegisterMethod(l, "newframe", celestia_newframe);
04561 RegisterMethod(l, "newvector", celestia_newvector);
04562 RegisterMethod(l, "newposition", celestia_newposition);
04563 RegisterMethod(l, "newrotation", celestia_newrotation);
04564 RegisterMethod(l, "getscripttime", celestia_getscripttime);
04565 RegisterMethod(l, "requestkeyboard", celestia_requestkeyboard);
04566 RegisterMethod(l, "takescreenshot", celestia_takescreenshot);
04567 RegisterMethod(l, "createcelscript", celestia_createcelscript);
04568 RegisterMethod(l, "requestsystemaccess", celestia_requestsystemaccess);
04569 RegisterMethod(l, "getscriptpath", celestia_getscriptpath);
04570
04571 lua_pop(l, 1);
04572 }
04573
04574
04575 bool LuaState::init(CelestiaCore* appCore)
04576 {
04577 initMaps();
04578
04579
04580 lua_baselibopen(state);
04581 lua_mathlibopen(state);
04582 lua_tablibopen(state);
04583 lua_strlibopen(state);
04584
04585
04586
04587
04588
04589
04590 if (loadScript("wait = function(x) coroutine.yield(x) end") != 0)
04591 return false;
04592 lua_pcall(state, 0, 0, 0);
04593
04594 lua_pushstring(state, "KM_PER_MICROLY");
04595 lua_pushnumber(state, (lua_Number)KM_PER_LY/1e6);
04596 lua_settable(state, LUA_GLOBALSINDEX);
04597
04598 CreateObjectMetaTable(state);
04599 CreateObserverMetaTable(state);
04600 CreateCelestiaMetaTable(state);
04601 CreatePositionMetaTable(state);
04602 CreateVectorMetaTable(state);
04603 CreateRotationMetaTable(state);
04604 CreateFrameMetaTable(state);
04605 CreateCelscriptMetaTable(state);
04606
04607
04608 lua_pushstring(state, "celestia");
04609 celestia_new(state, appCore);
04610 lua_settable(state, LUA_GLOBALSINDEX);
04611
04612 lua_pushstring(state, "celestia-appcore");
04613 lua_pushlightuserdata(state, static_cast<void*>(appCore));
04614 lua_settable(state, LUA_REGISTRYINDEX);
04615
04616 lua_pushstring(state, "celestia-luastate");
04617 lua_pushlightuserdata(state, static_cast<void*>(this));
04618 lua_settable(state, LUA_REGISTRYINDEX);
04619
04620 #if 0
04621 lua_pushstring(state, "dofile");
04622 lua_gettable(state, LUA_GLOBALSINDEX);
04623 lua_pushstring(state, "luainit.celx");
04624 if (lua_pcall(state, 1, 0, 0) != 0)
04625 {
04626 CelestiaCore::Alerter* alerter = appCore->getAlerter();
04627
04628 const char* errorMessage = lua_tostring(state, -1);
04629 cout << errorMessage << '\n'; cout.flush();
04630 alerter->fatalError(errorMessage);
04631 return false;
04632 }
04633 #endif
04634
04635 return true;
04636 }