celestiacore.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:147k
- // celestiacore.cpp
- //
- // Platform-independent UI handling and initialization for Celestia.
- // winmain, gtkmain, and glutmain are thin, platform-specific modules
- // that sit directly on top of CelestiaCore and feed it mouse and
- // keyboard events. CelestiaCore then turns those events into calls
- // to Renderer and Simulation.
- //
- // Copyright (C) 2001-2009, the Celestia Development Team
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- #include <cstdio>
- #include <iostream>
- #include <fstream>
- #include <iomanip>
- #include <algorithm>
- #include <cstdlib>
- #include <cctype>
- #include <cstring>
- #include <cassert>
- #include <ctime>
- #include <celengine/gl.h>
- #include <celmath/vecmath.h>
- #include <celmath/quaternion.h>
- #include <celmath/mathlib.h>
- #include <celutil/util.h>
- #include <celutil/filetype.h>
- #include <celutil/directory.h>
- #include <celutil/formatnum.h>
- #include <celengine/astro.h>
- #include <celengine/overlay.h>
- #include <celengine/console.h>
- #include <celengine/execution.h>
- #include <celengine/cmdparser.h>
- #include <celengine/multitexture.h>
- #include <celengine/spiceinterface.h>
- #include <celengine/axisarrow.h>
- #include <celengine/planetgrid.h>
- #include <celengine/visibleregion.h>
- #include "favorites.h"
- #include "celestiacore.h"
- #include <celutil/debug.h>
- #include <celutil/utf8.h>
- #include "url.h"
- #ifdef CELX
- #include <celengine/scriptobject.h>
- #endif
- #ifdef _WIN32
- #define TIMERATE_PRINTF_FORMAT "%.12g"
- #else
- #define TIMERATE_PRINTF_FORMAT "%'.12g"
- #endif
- using namespace std;
- static const int DragThreshold = 3;
- // Perhaps you'll want to put this stuff in configuration file.
- static const double CoarseTimeScaleFactor = 10.0;
- static const double FineTimeScaleFactor = 2.0;
- static const double fMinSlewRate = 3.0;
- static const double fMaxKeyAccel = 20.0;
- static const float fAltitudeThreshold = 4.0f;
- static const float RotationBraking = 10.0f;
- static const float RotationDecay = 2.0f;
- static const double MaximumTimeRate = 1.0e15;
- static const double MinimumTimeRate = 1.0e-15;
- static const float stdFOV = degToRad(45.0f);
- static const float MaximumFOV = degToRad(120.0f);
- static const float MinimumFOV = degToRad(0.001f);
- static float KeyRotationAccel = degToRad(120.0f);
- static float MouseRotationSensitivity = degToRad(1.0f);
- static const int ConsolePageRows = 10;
- static Console console(200, 120);
- static void warning(string s)
- {
- cout << s;
- }
- struct OverlayImage
- {
- Texture* texture;
- int xSize;
- int ySize;
- int left;
- int bottom;
- };
- vector<OverlayImage> overlayImages;
- // Extremely basic implementation of an ExecutionEnvironment for
- // running scripts.
- class CoreExecutionEnvironment : public ExecutionEnvironment
- {
- private:
- CelestiaCore& core;
- public:
- CoreExecutionEnvironment(CelestiaCore& _core) : core(_core)
- {
- }
- Simulation* getSimulation() const
- {
- return core.getSimulation();
- }
- Renderer* getRenderer() const
- {
- return core.getRenderer();
- }
- CelestiaCore* getCelestiaCore() const
- {
- return &core;
- }
- void showText(string s, int horig, int vorig, int hoff, int voff,
- double duration)
- {
- core.showText(s, horig, vorig, hoff, voff, duration);
- }
- };
- // If right dragging to rotate, adjust the rotation rate based on the
- // distance from the reference object. This makes right drag rotation
- // useful even when the camera is very near the surface of an object.
- // Disable adjustments if the reference is a deep sky object, since they
- // have no true surface (and the observer is likely to be inside one.)
- float ComputeRotationCoarseness(Simulation& sim)
- {
- float coarseness = 1.5f;
- Selection selection = sim.getActiveObserver()->getFrame()->getRefObject();
- if (selection.getType() == Selection::Type_Star ||
- selection.getType() == Selection::Type_Body)
- {
- double radius = selection.radius();
- double t = sim.getTime();
- UniversalCoord observerPosition = sim.getActiveObserver()->getPosition();
- UniversalCoord selectionPosition = selection.getPosition(t);
- double distance = astro::microLightYearsToKilometers(observerPosition.distanceTo(selectionPosition));
- double altitude = distance - radius;
- if (altitude > 0.0 && altitude < radius)
- {
- coarseness *= (float) max(0.01, altitude / radius);
- }
- }
- return coarseness;
- }
- View::View(View::Type _type,
- Observer* _observer,
- float _x, float _y,
- float _width, float _height) :
- type(_type),
- observer(_observer),
- parent(0),
- child1(0),
- child2(0),
- x(_x),
- y(_y),
- width(_width),
- height(_height),
- renderFlags(0),
- labelMode(0),
- zoom(1),
- alternateZoom(1)
- {
- }
- void View::mapWindowToView(float wx, float wy, float& vx, float& vy) const
- {
- vx = (wx - x) / width;
- vy = (wy + (y + height - 1)) / height;
- vx = (vx - 0.5f) * (width / height);
- vy = 0.5f - vy;
- }
- void View::walkTreeResize(View* sibling, int sign) {
- float ratio;
- switch (parent->type)
- {
- case View::HorizontalSplit:
- ratio = parent->height / (parent->height - height);
- sibling->height *= ratio;
- if (sign == 1)
- {
- sibling->y = parent->y + (sibling->y - parent->y) * ratio;
- }
- else
- {
- sibling->y = parent->y + (sibling->y - (y + height)) * ratio;
- }
- break;
- case View::VerticalSplit:
- ratio = parent->width / (parent->width - width);
- sibling->width *= ratio;
- if (sign == 1)
- {
- sibling->x = parent->x + (sibling->x - parent->x) * ratio;
- }
- else
- {
- sibling->x = parent->x + (sibling->x - (x + width) ) * ratio;
- }
- break;
- case View::ViewWindow:
- break;
- }
- if (sibling->child1) walkTreeResize(sibling->child1, sign);
- if (sibling->child2) walkTreeResize(sibling->child2, sign);
- }
- bool View::walkTreeResizeDelta(View* v, float delta, bool check)
- {
- View *p=v;
- int sign = -1;
- float ratio;
- double newSize;
- if (v->child1)
- {
- if (!walkTreeResizeDelta(v->child1, delta, check))
- return false;
- }
- if (v->child2)
- {
- if (!walkTreeResizeDelta(v->child2, delta, check))
- return false;
- }
- while ( p != child1 && p != child2 && (p = p->parent) ) ;
- if (p == child1) sign = 1;
- switch (type)
- {
- case View::HorizontalSplit:
- delta = -delta;
- ratio = (p->height + sign * delta) / p->height;
- newSize = v->height * ratio;
- if (newSize <= .1) return false;
- if (check) return true;
- v->height = (float) newSize;
- if (sign == 1)
- {
- v->y = p->y + (v->y - p->y) * ratio;
- }
- else
- {
- v->y = p->y + delta + (v->y - p->y) * ratio;
- }
- break;
- case View::VerticalSplit:
- ratio = (p->width + sign * delta) / p->width;
- newSize = v->width * ratio;
- if (newSize <= .1) return false;
- if (check) return true;
- v->width = (float) newSize;
- if (sign == 1)
- {
- v->x = p->x + (v->x - p->x) * ratio;
- }
- else
- {
- v->x = p->x + delta + (v->x - p->x) * ratio;
- }
- break;
- case View::ViewWindow:
- break;
- }
- return true;
- }
- CelestiaCore::CelestiaCore() :
- config(NULL),
- universe(NULL),
- favorites(NULL),
- destinations(NULL),
- sim(NULL),
- renderer(NULL),
- overlay(NULL),
- width(1),
- height(1),
- font(NULL),
- titleFont(NULL),
- messageText(""),
- messageHOrigin(0),
- messageVOrigin(0),
- messageHOffset(0),
- messageVOffset(0),
- messageStart(0.0),
- messageDuration(0.0),
- typedText(""),
- typedTextCompletionIdx(-1),
- textEnterMode(KbNormal),
- hudDetail(1),
- dateFormat(astro::Date::Locale),
- dateStrWidth(0),
- overlayElements(ShowTime | ShowVelocity | ShowSelection | ShowFrame),
- wireframe(false),
- editMode(false),
- altAzimuthMode(false),
- showConsole(false),
- lightTravelFlag(false),
- flashFrameStart(0.0),
- timer(NULL),
- runningScript(NULL),
- execEnv(NULL),
- #ifdef CELX
- celxScript(NULL),
- luaHook(NULL),
- luaSandbox(NULL),
- #endif // CELX
- scriptState(ScriptCompleted),
- timeZoneBias(0),
- showFPSCounter(false),
- nFrames(0),
- fps(0.0),
- fpsCounterStartTime(0.0),
- oldFOV(stdFOV),
- mouseMotion(0.0f),
- dollyMotion(0.0),
- dollyTime(0.0),
- zoomMotion(0.0),
- zoomTime(0.0),
- sysTime(0.0),
- currentTime(0.0),
- viewChanged(true),
- joystickRotation(0.0f, 0.0f, 0.0f),
- KeyAccel(1.0),
- movieCapture(NULL),
- recording(false),
- contextMenuCallback(NULL),
- logoTexture(NULL),
- alerter(NULL),
- cursorHandler(NULL),
- defaultCursorShape(CelestiaCore::CrossCursor),
- historyCurrent(0),
- activeView(views.begin()),
- showActiveViewFrame(false),
- showViewFrames(true),
- resizeSplit(0),
- screenDpi(96),
- distanceToScreen(400)
- {
- /* Get a renderer here so it may be queried for capabilities of the
- underlying engine even before rendering is enabled. It's initRenderer()
- routine will be called much later. */
- renderer = new Renderer();
- timer = CreateTimer();
- execEnv = new CoreExecutionEnvironment(*this);
- int i;
- for (i = 0; i < KeyCount; i++)
- {
- keysPressed[i] = false;
- shiftKeysPressed[i] = false;
- }
- for (i = 0; i < JoyButtonCount; i++)
- joyButtonsPressed[i] = false;
- clog.rdbuf(console.rdbuf());
- cerr.rdbuf(console.rdbuf());
- console.setWindowHeight(ConsolePageRows);
- }
- CelestiaCore::~CelestiaCore()
- {
- if (movieCapture != NULL)
- recordEnd();
- #ifdef CELX
- // Clean up all scripts
- if (celxScript != NULL)
- delete celxScript;
- if (luaHook != NULL)
- delete luaHook;
- if (luaSandbox != NULL)
- delete luaSandbox;
- #endif
- delete execEnv;
- }
- void CelestiaCore::readFavoritesFile()
- {
- // Set up favorites list
- if (config->favoritesFile != "")
- {
- ifstream in(config->favoritesFile.c_str(), ios::in);
- if (in.good())
- {
- favorites = ReadFavoritesList(in);
- if (favorites == NULL)
- {
- warning(_("Error reading favorites file."));
- }
- }
- }
- }
- void CelestiaCore::writeFavoritesFile()
- {
- if (config->favoritesFile != "")
- {
- ofstream out(config->favoritesFile.c_str(), ios::out);
- if (out.good())
- WriteFavoritesList(*favorites, out);
- }
- }
- void CelestiaCore::activateFavorite(FavoritesEntry& fav)
- {
- sim->cancelMotion();
- sim->setTime(fav.jd);
- sim->setObserverPosition(fav.position);
- sim->setObserverOrientation(fav.orientation);
- sim->setSelection(sim->findObjectFromPath(fav.selectionName));
- sim->setFrame(fav.coordSys, sim->getSelection());
- }
- void CelestiaCore::addFavorite(string name, string parentFolder, FavoritesList::iterator* iter)
- {
- FavoritesList::iterator pos;
- if(!iter)
- pos = favorites->end();
- else
- pos = *iter;
- FavoritesEntry* fav = new FavoritesEntry();
- fav->jd = sim->getTime();
- fav->position = sim->getObserver().getPosition();
- fav->orientation = sim->getObserver().getOrientationf();
- fav->name = name;
- fav->isFolder = false;
- fav->parentFolder = parentFolder;
- Selection sel = sim->getSelection();
- if (sel.deepsky() != NULL)
- fav->selectionName = sim->getUniverse()->getDSOCatalog()->getDSOName(sel.deepsky());
- else
- fav->selectionName = sel.getName();
- fav->coordSys = sim->getFrame()->getCoordinateSystem();
- favorites->insert(pos, fav);
- }
- void CelestiaCore::addFavoriteFolder(string name, FavoritesList::iterator* iter)
- {
- FavoritesList::iterator pos;
- if(!iter)
- pos = favorites->end();
- else
- pos = *iter;
- FavoritesEntry* fav = new FavoritesEntry();
- fav->name = name;
- fav->isFolder = true;
- favorites->insert(pos, fav);
- }
- FavoritesList* CelestiaCore::getFavorites()
- {
- return favorites;
- }
- const DestinationList* CelestiaCore::getDestinations()
- {
- return destinations;
- }
- // Used in the super-secret edit mode
- void showSelectionInfo(const Selection& sel)
- {
- Vec3f axis(0.0f, 1.0, 0.0f);
- float angle = 0.0f;
- if (sel.deepsky() != NULL)
- sel.deepsky()->getOrientation().getAxisAngle(axis, angle);
- else if (sel.body() != NULL)
- sel.body()->getOrientation().getAxisAngle(axis, angle);
- cout << sel.getName() << 'n';
- cout << _("Orientation: ") << '[' << axis.x << ',' << axis.y << ',' << axis.z << "], " << radToDeg(angle) << 'n';
- }
- void CelestiaCore::cancelScript()
- {
- if (runningScript != NULL)
- {
- delete runningScript;
- scriptState = ScriptCompleted;
- runningScript = NULL;
- }
- #ifdef CELX
- if (celxScript != NULL)
- {
- celxScript->cleanup();
- if (textEnterMode & KbPassToScript)
- setTextEnterMode(textEnterMode & ~KbPassToScript);
- scriptState = ScriptCompleted;
- }
- #endif
- }
- void CelestiaCore::runScript(CommandSequence* script)
- {
- cancelScript();
- if (runningScript == NULL && script != NULL && scriptState == ScriptCompleted)
- {
- scriptState = ScriptRunning;
- runningScript = new Execution(*script, *execEnv);
- }
- }
- void CelestiaCore::runScript(const string& filename)
- {
- cancelScript();
- string localeFilename = LocaleFilename(filename);
- ContentType type = DetermineFileType(localeFilename);
- if (type == Content_CelestiaLegacyScript)
- {
- ifstream scriptfile(localeFilename.c_str());
- if (!scriptfile.good())
- {
- if (alerter != NULL)
- alerter->fatalError(_("Error opening script file."));
- else
- flash(_("Error opening script file."));
- }
- else
- {
- CommandParser parser(scriptfile);
- CommandSequence* script = parser.parse();
- if (script == NULL)
- {
- const vector<string>* errors = parser.getErrors();
- const char* errorMsg = "";
- if (errors->size() > 0)
- errorMsg = (*errors)[0].c_str();
- if (alerter != NULL)
- alerter->fatalError(errorMsg);
- else
- flash(errorMsg);
- }
- else
- {
- runningScript = new Execution(*script, *execEnv);
- scriptState = sim->getPauseState()?ScriptPaused:ScriptRunning;
- }
- }
- }
- #ifdef CELX
- else if (type == Content_CelestiaScript)
- {
- ifstream scriptfile(localeFilename.c_str());
- if (!scriptfile.good())
- {
- char errMsg[1024];
- sprintf(errMsg, _("Error opening script '%s'"), localeFilename.c_str());
- if (alerter != NULL)
- alerter->fatalError(errMsg);
- else
- flash(errMsg);
- }
- if (celxScript == NULL)
- {
- celxScript = new LuaState();
- celxScript->init(this);
- }
- int status = celxScript->loadScript(scriptfile, localeFilename);
- if (status != 0)
- {
- string errMsg = celxScript->getErrorMessage();
- if (errMsg.empty())
- errMsg = _("Unknown error opening script");
- if (alerter != NULL)
- alerter->fatalError(errMsg);
- else
- flash(errMsg);
- }
- else
- {
- // Coroutine execution; control may be transferred between the
- // script and Celestia's event loop
- if (!celxScript->createThread())
- {
- const char* errMsg = _("Script coroutine initialization failed");
- if (alerter != NULL)
- alerter->fatalError(errMsg);
- else
- flash(errMsg);
- }
- else
- {
- scriptState = sim->getPauseState()?ScriptPaused:ScriptRunning;
- }
- }
- }
- #endif
- else
- {
- if (alerter != NULL)
- alerter->fatalError(_("Invalid filetype"));
- else
- flash(_("Invalid filetype"));
- }
- }
- bool checkMask(int modifiers, int mask)
- {
- return (modifiers & mask) == mask;
- }
- void CelestiaCore::mouseButtonDown(float x, float y, int button)
- {
- setViewChanged();
- mouseMotion = 0.0f;
- #ifdef CELX
- if (celxScript != NULL)
- {
- if (celxScript->handleMouseButtonEvent(x, y, button, true))
- return;
- }
- if (luaHook && luaHook->callLuaHook(this, "mousebuttondown", x, y, button))
- return;
- #endif
- if (views.size() > 1)
- {
- // To select the clicked into view before a drag.
- pickView(x, y);
- }
- if (views.size() > 1 && button == LeftButton) // look if click is near a view border
- {
- View *v1 = 0, *v2 = 0;
- for (list<View*>::iterator i = views.begin(); i != views.end(); i++)
- {
- View* v = *i;
- if (v->type == View::ViewWindow)
- {
- float vx, vy, vxp, vyp;
- vx = ( x / width - v->x ) / v->width;
- vy = ( (1 - y / height ) - v->y ) / v->height;
- vxp = vx * v->width * width;
- vyp = vy * v->height * height;
- if ( (vx >=0 && vx <= 1 && ( abs(vyp) <= 2 || abs(vyp - v->height * height) <= 2))
- || (vy >=0 && vy <= 1 && ( abs(vxp) <= 2 || abs(vxp - v->width * width) <= 2)) )
- {
- if (v1 == 0)
- {
- v1 = v;
- }
- else
- {
- v2 = v;
- break;
- }
- }
- }
- }
- if (v2 != 0) {
- // Look for common ancestor to v1 & v2 = split being draged.
- View *p1 = v1, *p2 = v2;
- while ( (p1 = p1->parent) )
- {
- p2 = v2;
- while ( (p2 = p2->parent) && p1 != p2) ;
- if (p2 != 0) break;
- }
- if (p2 != 0)
- {
- resizeSplit = p1;
- }
- }
- }
- }
- void CelestiaCore::mouseButtonUp(float x, float y, int button)
- {
- setViewChanged();
- // Four pixel tolerance for picking
- float pickTolerance = sim->getActiveObserver()->getFOV() / height * 4.0f;
- if (resizeSplit)
- {
- resizeSplit = 0;
- return;
- }
- #ifdef CELX
- if (celxScript != NULL)
- {
- if (celxScript->handleMouseButtonEvent(x, y, button, false))
- return;
- }
- if (luaHook && luaHook->callLuaHook(this,"mousebuttonup", x, y, button))
- return;
- #endif
- // If the mouse hasn't moved much since it was pressed, treat this
- // as a selection or context menu event. Otherwise, assume that the
- // mouse was dragged and ignore the event.
- if (mouseMotion < DragThreshold)
- {
- if (button == LeftButton)
- {
- pickView(x, y);
- float pickX, pickY;
- float aspectRatio = ((float) width / (float) height);
- (*activeView)->mapWindowToView((float) x / (float) width,
- (float) y / (float) height,
- pickX, pickY);
- Vec3f pickRay =
- sim->getActiveObserver()->getPickRay(pickX * aspectRatio, pickY);
- Selection oldSel = sim->getSelection();
- Selection newSel = sim->pickObject(pickRay, renderer->getRenderFlags(), pickTolerance);
- addToHistory();
- sim->setSelection(newSel);
- if (!oldSel.empty() && oldSel == newSel)
- sim->centerSelection();
- }
- else if (button == RightButton)
- {
- float pickX, pickY;
- float aspectRatio = ((float) width / (float) height);
- (*activeView)->mapWindowToView((float) x / (float) width,
- (float) y / (float) height,
- pickX, pickY);
- Vec3f pickRay =
- sim->getActiveObserver()->getPickRay(pickX * aspectRatio, pickY);
- Selection sel = sim->pickObject(pickRay, renderer->getRenderFlags(), pickTolerance);
- if (!sel.empty())
- {
- if (contextMenuCallback != NULL)
- contextMenuCallback(x, y, sel);
- }
- }
- else if (button == MiddleButton)
- {
- if ((*activeView)->zoom != 1)
- {
- (*activeView)->alternateZoom = (*activeView)->zoom;
- (*activeView)->zoom = 1;
- }
- else
- {
- (*activeView)->zoom = (*activeView)->alternateZoom;
- }
- setFOVFromZoom();
- // If AutoMag, adapt the faintestMag to the new fov
- if((renderer->getRenderFlags() & Renderer::ShowAutoMag) != 0)
- setFaintestAutoMag();
- }
- }
- }
- void CelestiaCore::mouseWheel(float motion, int modifiers)
- {
- setViewChanged();
- if (config->reverseMouseWheel) motion = -motion;
- if (motion != 0.0)
- {
- if ((modifiers & ShiftKey) != 0)
- {
- zoomTime = currentTime;
- zoomMotion = 0.25f * motion;
- }
- else
- {
- dollyTime = currentTime;
- dollyMotion = 0.25f * motion;
- }
- }
- }
- /// Handles cursor shape changes on view borders if the cursorHandler is defined.
- /// This must be called on mouse move events on the OpenGL Widget.
- /// x and y are the pixel coordinates relative to the widget.
- void CelestiaCore::mouseMove(float x, float y)
- {
- if (views.size() > 1 && cursorHandler != NULL)
- {
- /*View* v1 = 0; Unused*/
- /*View* v2 = 0; Unused*/
- for (list<View*>::iterator i = views.begin(); i != views.end(); i++)
- {
- View* v = *i;
- if (v->type == View::ViewWindow)
- {
- float vx, vy, vxp, vyp;
- vx = (x / width - v->x) / v->width;
- vy = ((1 - y / height) - v->y ) / v->height;
- vxp = vx * v->width * width;
- vyp = vy * v->height * height;
- if (vx >=0 && vx <= 1 && (abs(vyp) <= 2 || abs(vyp - v->height * height) <= 2))
- {
- cursorHandler->setCursorShape(CelestiaCore::SizeVerCursor);
- return;
- }
- else if (vy >=0 && vy <= 1 && (abs(vxp) <= 2 || abs(vxp - v->width * width) <= 2))
- {
- cursorHandler->setCursorShape(CelestiaCore::SizeHorCursor);
- return;
- }
- }
- }
- cursorHandler->setCursorShape(defaultCursorShape);
- }
- return;
- }
- void CelestiaCore::mouseMove(float dx, float dy, int modifiers)
- {
- if (modifiers != 0)
- setViewChanged();
- if (resizeSplit != 0)
- {
- switch(resizeSplit->type) {
- case View::HorizontalSplit:
- if ( resizeSplit->walkTreeResizeDelta(resizeSplit->child1, dy / height, true)
- && resizeSplit->walkTreeResizeDelta(resizeSplit->child2, dy / height, true))
- {
- resizeSplit->walkTreeResizeDelta(resizeSplit->child1, dy / height, false);
- resizeSplit->walkTreeResizeDelta(resizeSplit->child2, dy / height, false);
- }
- break;
- case View::VerticalSplit:
- if ( resizeSplit->walkTreeResizeDelta(resizeSplit->child1, dx / width, true)
- && resizeSplit->walkTreeResizeDelta(resizeSplit->child2, dx / width, true)
- )
- {
- resizeSplit->walkTreeResizeDelta(resizeSplit->child1, dx / width, false);
- resizeSplit->walkTreeResizeDelta(resizeSplit->child2, dx / width, false);
- }
- break;
- case View::ViewWindow:
- break;
- }
- setFOVFromZoom();
- return;
- }
- #ifdef CELX
- if (luaHook &&
- luaHook->callLuaHook(this,"mousebuttonmove", dx, dy, modifiers))
- {
- return;
- }
- #endif
- if ((modifiers & (LeftButton | RightButton)) != 0)
- {
- if (editMode && checkMask(modifiers, LeftButton | ShiftKey | ControlKey))
- {
- // Rotate the selected object
- Selection sel = sim->getSelection();
- Quatf q(1);
- if (sel.getType() == Selection::Type_DeepSky)
- q = sel.deepsky()->getOrientation();
- else if (sel.getType() == Selection::Type_Body)
- q = sel.body()->getOrientation();
- q.yrotate(dx / width);
- q.xrotate(dy / height);
- if (sel.getType() == Selection::Type_DeepSky)
- sel.deepsky()->setOrientation(q);
- else if (sel.getType() == Selection::Type_Body)
- sel.body()->setOrientation(q);
- }
- else if (editMode && checkMask(modifiers, RightButton | ShiftKey | ControlKey))
- {
- // Rotate the selected object about an axis from its center to the
- // viewer.
- Selection sel = sim->getSelection();
- if (sel.deepsky() != NULL)
- {
- double t = sim->getTime();
- Vec3d v = sel.getPosition(t) - sim->getObserver().getPosition();
- Vec3f axis((float) v.x, (float) v.y, (float) v.z);
- axis.normalize();
- Quatf r;
- r.setAxisAngle(axis, dx / width);
- Quatf q = sel.deepsky()->getOrientation();
- sel.deepsky()->setOrientation(r * q);
- }
- }
- else if (checkMask(modifiers, LeftButton | RightButton) ||
- checkMask(modifiers, LeftButton | ControlKey))
- {
- // Y-axis controls distance (exponentially), and x-axis motion
- // rotates the camera about the view normal.
- float amount = dy / height;
- sim->changeOrbitDistance(amount * 5);
- if (dx * dx > dy * dy)
- {
- Observer& observer = sim->getObserver();
- Vec3d v = Vec3d(0, 0, dx * -MouseRotationSensitivity);
- Quatd obsOrientation = observer.getOrientation();
- Quatd dr = 0.5 * (v * obsOrientation);
- obsOrientation += dr;
- obsOrientation.normalize();
- observer.setOrientation(obsOrientation);
- }
- }
- else if (checkMask(modifiers, LeftButton | ShiftKey))
- {
- // Mouse zoom control
- float amount = dy / height;
- float minFOV = MinimumFOV;
- float maxFOV = MaximumFOV;
- float fov = sim->getActiveObserver()->getFOV();
- // In order for the zoom to have the right feel, it should be
- // exponential.
- float newFOV = minFOV + (float) exp(log(fov - minFOV) + amount * 4);
- if (newFOV > maxFOV)
- newFOV = maxFOV;
- if (newFOV > minFOV)
- {
- sim->getActiveObserver()->setFOV(newFOV);
- setZoomFromFOV();
- }
- if ((renderer->getRenderFlags() & Renderer::ShowAutoMag))
- {
- setFaintestAutoMag();
- char buf[128];
- sprintf(buf, _("Magnitude limit: %.2f"), sim->getFaintestVisible());
- flash(buf);
- }
- }
- else
- {
- Quatf q(1);
- // For a small field of view, rotate the camera more finely
- float coarseness = 1.5f;
- if ((modifiers & RightButton) == 0)
- {
- coarseness = radToDeg(sim->getActiveObserver()->getFOV()) / 30.0f;
- }
- else
- {
- // If right dragging to rotate, adjust the rotation rate
- // based on the distance from the reference object.
- coarseness = ComputeRotationCoarseness(*sim);
- }
- q.yrotate(dx / width * coarseness);
- q.xrotate(dy / height * coarseness);
- if ((modifiers & RightButton) != 0)
- sim->orbit(q);
- else
- sim->rotate(~q);
- }
- mouseMotion += abs(dy) + abs(dx);
- }
- }
- /// Makes the view under x, y the active view.
- void CelestiaCore::pickView(float x, float y)
- {
- if (x+2 < (*activeView)->x * width || x-2 > ((*activeView)->x + (*activeView)->width) * width
- || (height - y)+2 < (*activeView)->y * height || (height - y)-2 > ((*activeView)->y + (*activeView)->height) * height)
- {
- activeView = views.begin();
- while ( (activeView != views.end())
- &&
- ( (x+2 < (*activeView)->x * width || x-2 > ((*activeView)->x + (*activeView)->width) * width || (height - y)+2 < (*activeView)->y * height || (height - y)-2 > ((*activeView)->y + (*activeView)->height) * height)
- ||
- ((*activeView)->type != View::ViewWindow)
- )
- )
- {
- activeView++;
- }
-
- // Make sure that we're left with a valid view
- if (activeView == views.end())
- {
- activeView = views.begin();
- }
- sim->setActiveObserver((*activeView)->observer);
- if (!showActiveViewFrame)
- flashFrameStart = currentTime;
- return;
- }
- }
- void CelestiaCore::joystickAxis(int axis, float amount)
- {
- setViewChanged();
- float deadZone = 0.25f;
- if (abs(amount) < deadZone)
- amount = 0.0f;
- else
- amount = (amount - deadZone) * (1.0f / (1.0f - deadZone));
- amount = sign(amount) * square(amount);
- if (axis == Joy_XAxis)
- joystickRotation.y = amount;
- else if (axis == Joy_YAxis)
- joystickRotation.x = -amount;
- }
- void CelestiaCore::joystickButton(int button, bool down)
- {
- setViewChanged();
- if (button >= 0 && button < JoyButtonCount)
- joyButtonsPressed[button] = down;
- }
- static void scrollConsole(Console& con, int lines)
- {
- int topRow = con.getWindowRow();
- int height = con.getHeight();
- if (lines < 0)
- {
- if (topRow + lines > -height)
- console.setWindowRow(topRow + lines);
- else
- console.setWindowRow(-(height - 1));
- }
- else
- {
- if (topRow + lines <= -ConsolePageRows)
- console.setWindowRow(topRow + lines);
- else
- console.setWindowRow(-ConsolePageRows);
- }
- }
- void CelestiaCore::keyDown(int key, int modifiers)
- {
- setViewChanged();
- #ifdef CELX
- // TODO: should pass modifiers as a Lua table
- if (luaHook && luaHook->callLuaHook(this,
- "keydown",
- (float) key, (float) modifiers))
- {
- return;
- }
- #endif
- switch (key)
- {
- case Key_F1:
- sim->setTargetSpeed(0);
- break;
- case Key_F2:
- sim->setTargetSpeed(astro::kilometersToMicroLightYears(1.0f));
- break;
- case Key_F3:
- sim->setTargetSpeed(astro::kilometersToMicroLightYears(1000.0f));
- break;
- case Key_F4:
- sim->setTargetSpeed((float) astro::kilometersToMicroLightYears(astro::speedOfLight));
- break;
- case Key_F5:
- sim->setTargetSpeed((float) astro::kilometersToMicroLightYears(astro::speedOfLight * 10.0));
- break;
- case Key_F6:
- sim->setTargetSpeed(astro::AUtoMicroLightYears(1.0f));
- break;
- case Key_F7:
- sim->setTargetSpeed(1e6);
- break;
- case Key_F11:
- if (movieCapture != NULL)
- {
- if (isRecording())
- recordPause();
- else
- recordBegin();
- }
- break;
- case Key_F12:
- if (movieCapture != NULL)
- recordEnd();
- break;
- case Key_NumPad2:
- case Key_NumPad4:
- case Key_NumPad6:
- case Key_NumPad7:
- case Key_NumPad8:
- case Key_NumPad9:
- sim->setTargetSpeed(sim->getTargetSpeed());
- break;
- case Key_Down:
- if (showConsole)
- scrollConsole(console, 1);
- break;
- case Key_Up:
- if (showConsole)
- scrollConsole(console, -1);
- break;
- case Key_PageDown:
- if (showConsole)
- scrollConsole(console, ConsolePageRows);
- else
- back();
- break;
- case Key_PageUp:
- if (showConsole)
- scrollConsole(console, -ConsolePageRows);
- else
- forward();
- break;
- }
- if (KeyAccel < fMaxKeyAccel)
- KeyAccel *= 1.1;
- // Only process alphanumeric keys if we're not in text enter mode
- if (islower(key))
- key = toupper(key);
- if (!(key >= 'A' && key <= 'Z' && (textEnterMode != KbNormal) ))
- {
- if (modifiers & ShiftKey)
- shiftKeysPressed[key] = true;
- else
- keysPressed[key] = true;
- }
- }
- void CelestiaCore::keyUp(int key, int)
- {
- setViewChanged();
- KeyAccel = 1.0;
- if (islower(key))
- key = toupper(key);
- keysPressed[key] = false;
- shiftKeysPressed[key] = false;
- }
- #ifdef CELX
- static bool getKeyName(const char* c, int modifiers, char* keyName, unsigned int keyNameLength)
- {
- unsigned int length = strlen(c);
- // Translate control characters
- if (length == 1 && c[0] >= ' 01' && c[0] <= ' 32')
- {
- if (keyNameLength < 4)
- return false;
- sprintf(keyName, "C-%c", '140' + c[0]);
- }
- else if (modifiers & CelestiaCore::ControlKey)
- {
- if (keyNameLength < length + 4)
- return false;
- sprintf(keyName, "C-%s", c);
- }
- else
- {
- if (keyNameLength < length + 1)
- return false;
- strcpy(keyName, c);
- }
- return true;
- }
- #endif
- void CelestiaCore::charEntered(char c, int modifiers)
- {
- setViewChanged();
- char C[2];
- C[0] = c;
- C[1] = ' ';
- charEntered(C, modifiers);
- }
- void CelestiaCore::charEntered(const char *c_p, int modifiers)
- {
- setViewChanged();
- Observer* observer = sim->getActiveObserver();
- char c = *c_p;
- #ifdef CELX
- if (celxScript != NULL && (textEnterMode & KbPassToScript))
- {
- if (c != ' 33' && celxScript->charEntered(c_p))
- {
- return;
- }
- }
- #endif
- if (textEnterMode & KbAutoComplete)
- {
- wchar_t wc = 0; // Null wide character
- UTF8Decode(c_p, 0, strlen(c_p), wc);
- #ifdef TARGET_OS_MAC
- if ( wc && (!iscntrl(wc)) )
- #else
- if ( wc && (!iswcntrl(wc)) )
- #endif
- {
- typedText += string(c_p);
- typedTextCompletion = sim->getObjectCompletion(typedText, (renderer->getLabelMode() & Renderer::LocationLabels) != 0);
- typedTextCompletionIdx = -1;
- #ifdef AUTO_COMPLETION
- if (typedTextCompletion.size() == 1)
- {
- string::size_type pos = typedText.rfind('/', typedText.length());
- if (pos != string::npos)
- typedText = typedText.substr(0, pos + 1) + typedTextCompletion[0];
- else
- typedText = typedTextCompletion[0];
- }
- #endif
- }
- else if (c == 'b')
- {
- typedTextCompletionIdx = -1;
- if (typedText.size() > 0)
- {
- #ifdef AUTO_COMPLETION
- do
- {
- #endif
- // We remove bytes like b10xxx xxxx at the end of typeText
- // these are guarantied to not be the first byte of a UTF-8 char
- while (typedText.size() && ((typedText[typedText.size() - 1] & 0xC0) == 0x80)) {
- typedText = string(typedText, 0, typedText.size() - 1);
- }
- // We then remove the first byte of the last UTF-8 char of typedText.
- typedText = string(typedText, 0, typedText.size() - 1);
- if (typedText.size() > 0)
- {
- typedTextCompletion = sim->getObjectCompletion(typedText, (renderer->getLabelMode() & Renderer::LocationLabels) != 0);
- } else {
- typedTextCompletion.clear();
- }
- #ifdef AUTO_COMPLETION
- } while (typedText.size() > 0 && typedTextCompletion.size() == 1);
- #endif
- }
- }
- else if (c == ' 11') // TAB
- {
- if (typedTextCompletionIdx + 1 < (int) typedTextCompletion.size())
- typedTextCompletionIdx++;
- else if ((int) typedTextCompletion.size() > 0 && typedTextCompletionIdx + 1 == (int) typedTextCompletion.size())
- typedTextCompletionIdx = 0;
- if (typedTextCompletionIdx >= 0) {
- string::size_type pos = typedText.rfind('/', typedText.length());
- if (pos != string::npos)
- typedText = typedText.substr(0, pos + 1) + typedTextCompletion[typedTextCompletionIdx];
- else
- typedText = typedTextCompletion[typedTextCompletionIdx];
- }
- }
- else if (c == Key_BackTab)
- {
- if (typedTextCompletionIdx > 0)
- typedTextCompletionIdx--;
- else if (typedTextCompletionIdx == 0)
- typedTextCompletionIdx = typedTextCompletion.size() - 1;
- else if (typedTextCompletion.size() > 0)
- typedTextCompletionIdx = typedTextCompletion.size() - 1;
- if (typedTextCompletionIdx >= 0) {
- string::size_type pos = typedText.rfind('/', typedText.length());
- if (pos != string::npos)
- typedText = typedText.substr(0, pos + 1) + typedTextCompletion[typedTextCompletionIdx];
- else
- typedText = typedTextCompletion[typedTextCompletionIdx];
- }
- }
- else if (c == ' 33') // ESC
- {
- setTextEnterMode(textEnterMode & ~KbAutoComplete);
- }
- else if (c == 'n' || c == 'r')
- {
- if (typedText != "")
- {
- Selection sel = sim->findObjectFromPath(typedText, true);
- if (!sel.empty())
- {
- addToHistory();
- sim->setSelection(sel);
- }
- typedText = "";
- }
- setTextEnterMode(textEnterMode & ~KbAutoComplete);
- }
- return;
- }
- #ifdef CELX
- if (celxScript != NULL)
- {
- if (c != ' 33')
- {
- char keyName[8];
- getKeyName(c_p, modifiers, keyName, sizeof(keyName));
- if (celxScript->handleKeyEvent(keyName))
- return;
- }
- }
- if (luaHook)
- {
- char keyName[8];
- getKeyName(c_p, modifiers, keyName, sizeof(keyName));
- if (luaHook->callLuaHook(this, "charentered", keyName))
- {
- return;
- }
- }
- #endif
- char C = toupper(c);
- switch (C)
- {
- case ' 01': // Ctrl+A
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowAtmospheres);
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 02': // Ctrl+B
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowBoundaries);
- notifyWatchers(RenderFlagsChanged);
- break;
- case 'n':
- case 'r':
- setTextEnterMode(textEnterMode | KbAutoComplete);
- break;
- case 'b':
- sim->setSelection(sim->getSelection().parent());
- break;
- case ' 14': // Ctrl+L
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowNightMaps);
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 13': // Ctrl+K
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowMarkers);
- if (renderer->getRenderFlags() & Renderer::ShowMarkers)
- {
- flash(_("Markers enabled"));
- }
- else
- flash(_("Markers disabled"));
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 05': // Ctrl+E
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowEclipseShadows);
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 07': // Ctrl+G
- flash(_("Goto surface"));
- addToHistory();
- //if (sim->getFrame().coordSys == astro::Universal)
- sim->geosynchronousFollow();
- sim->gotoSurface(5.0);
- // sim->gotoSelection(0.0001, Vec3f(0, 1, 0), astro::ObserverLocal);
- break;
- case ' 06': // Ctrl+F
- addToHistory();
- altAzimuthMode = !altAzimuthMode;
- if (altAzimuthMode)
- {
- flash(_("Alt-azimuth mode enabled"));
- }
- else
- flash(_("Alt-azimuth mode disabled"));
- break;
- case 127: // Delete
- deleteView();
- break;
- case ' 11': // TAB
- do
- {
- activeView++;
- if (activeView == views.end())
- activeView = views.begin();
- } while ((*activeView)->type != View::ViewWindow);
- sim->setActiveObserver((*activeView)->observer);
- if (!showActiveViewFrame)
- flashFrameStart = currentTime;
- break;
- case ' 20': // Ctrl+P
- if (!sim->getSelection().empty())
- {
- Selection sel = sim->getSelection();
- if (sim->getUniverse()->isMarked(sel, 1))
- {
- sim->getUniverse()->unmarkObject(sel, 1);
- }
- else
- {
- MarkerRepresentation markerRep(MarkerRepresentation::Diamond);
- markerRep.setSize(10.0f);
- markerRep.setColor(Color(0.0f, 1.0f, 0.0f, 0.9f));
-
- sim->getUniverse()->markObject(sel, markerRep, 1);
- }
- }
- break;
- case ' 25': // Ctrl+U
- splitView(View::VerticalSplit);
- break;
- case ' 22': // Ctrl+R
- splitView(View::HorizontalSplit);
- break;
- case ' 04': // Ctrl+D
- singleView();
- break;
- case ' 23': // Ctrl+S
- renderer->setStarStyle((Renderer::StarStyle) (((int) renderer->getStarStyle() + 1) %
- (int) Renderer::StarStyleCount));
- switch (renderer->getStarStyle())
- {
- case Renderer::FuzzyPointStars:
- flash(_("Star style: fuzzy points"));
- break;
- case Renderer::PointStars:
- flash(_("Star style: points"));
- break;
- case Renderer::ScaledDiscStars:
- flash(_("Star style: scaled discs"));
- break;
- default:
- break;
- }
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 24': // Ctrl+T
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowCometTails);
- if (renderer->getRenderFlags() & Renderer::ShowCometTails)
- {
- flash(_("Comet tails enabled"));
- }
- else
- flash(_("Comet tails disabled"));
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 26': // Ctrl+V
- {
- GLContext* context = renderer->getGLContext();
- GLContext::GLRenderPath path = context->getRenderPath();
- GLContext::GLRenderPath newPath = context->nextRenderPath();
- if (newPath != path)
- {
- switch (newPath)
- {
- case GLContext::GLPath_Basic:
- flash(_("Render path: Basic"));
- break;
- case GLContext::GLPath_Multitexture:
- flash(_("Render path: Multitexture"));
- break;
- case GLContext::GLPath_NvCombiner:
- flash(_("Render path: NVIDIA combiners"));
- break;
- case GLContext::GLPath_DOT3_ARBVP:
- flash(_("Render path: OpenGL vertex program"));
- break;
- case GLContext::GLPath_NvCombiner_NvVP:
- flash(_("Render path: NVIDIA vertex program and combiners"));
- break;
- case GLContext::GLPath_NvCombiner_ARBVP:
- flash(_("Render path: OpenGL vertex program/NVIDIA combiners"));
- break;
- case GLContext::GLPath_ARBFP_ARBVP:
- flash(_("Render path: OpenGL 1.5 vertex/fragment program"));
- break;
- case GLContext::GLPath_NV30:
- flash(_("Render path: NVIDIA GeForce FX"));
- break;
- case GLContext::GLPath_GLSL:
- flash(_("Render path: OpenGL 2.0"));
- break;
- }
- context->setRenderPath(newPath);
- notifyWatchers(RenderFlagsChanged);
- }
- }
- break;
- case ' 27': // Ctrl+W
- wireframe = !wireframe;
- renderer->setRenderMode(wireframe ? GL_LINE : GL_FILL);
- break;
- case ' 30': // Ctrl+X
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowSmoothLines);
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 31': // Ctrl+Y
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowAutoMag);
- if (renderer->getRenderFlags() & Renderer::ShowAutoMag)
- {
- flash(_("Auto-magnitude enabled"));
- setFaintestAutoMag();
- }
- else
- {
- flash(_("Auto-magnitude disabled"));
- }
- notifyWatchers(RenderFlagsChanged);
- break;
- case ' 33': // Escape
- cancelScript();
- addToHistory();
- if (textEnterMode != KbNormal)
- {
- setTextEnterMode(KbNormal);
- }
- else
- {
- if (sim->getObserverMode() == Observer::Travelling)
- sim->setObserverMode(Observer::Free);
- else
- sim->setFrame(ObserverFrame::Universal, Selection());
- if (!sim->getTrackedObject().empty())
- sim->setTrackedObject(Selection());
- }
- flash(_("Cancel"));
- break;
- case ' ':
- if (sim->getPauseState() == true)
- {
- if (scriptState == ScriptPaused)
- scriptState = ScriptRunning;
- sim->setPauseState(false);
- }
- else
- {
- sim->setPauseState(true);
- // If there's a script running then pause it. This has the
- // potentially confusing side effect of rendering nonfunctional
- // goto, center, and other movement commands.
- #ifdef CELX
- if (runningScript != NULL || celxScript != NULL)
- #else
- if (runningScript != NULL)
- #endif
- {
- if (scriptState == ScriptRunning)
- scriptState = ScriptPaused;
- }
- else
- {
- if (scriptState == ScriptPaused)
- scriptState = ScriptRunning;
- }
- }
- if (sim->getPauseState() == true)
- {
- if (scriptState == ScriptPaused)
- flash(_("Time and script are paused"));
- else
- flash(_("Time is paused"));
- }
- else
- {
- flash(_("Resume"));
- }
- break;
- case '!':
- if (editMode)
- {
- showSelectionInfo(sim->getSelection());
- }
- else
- {
- time_t t = time(NULL);
- struct tm *gmt = gmtime(&t);
- if (gmt != NULL)
- {
- astro::Date d;
- d.year = gmt->tm_year + 1900;
- d.month = gmt->tm_mon + 1;
- d.day = gmt->tm_mday;
- d.hour = gmt->tm_hour;
- d.minute = gmt->tm_min;
- d.seconds = (int) gmt->tm_sec;
- sim->setTime(astro::UTCtoTDB(d));
- }
- }
- break;
- case '%':
- {
- const ColorTemperatureTable* current =
- renderer->getStarColorTable();
- if (current == GetStarColorTable(ColorTable_Enhanced))
- {
- renderer->setStarColorTable(GetStarColorTable(ColorTable_Blackbody_D65));
- }
- else if (current == GetStarColorTable(ColorTable_Blackbody_D65))
- {
- renderer->setStarColorTable(GetStarColorTable(ColorTable_Enhanced));
- }
- else
- {
- // Unknown color table
- }
- }
- break;
- case '^':
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowNebulae);
- notifyWatchers(RenderFlagsChanged);
- break;
- case '&':
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::LocationLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case '*':
- addToHistory();
- sim->reverseObserverOrientation();
- break;
- case '?':
- addToHistory();
- if (!sim->getSelection().empty())
- {
- Vec3d v = sim->getSelection().getPosition(sim->getTime()) -
- sim->getObserver().getPosition();
- int hours, mins;
- float secs;
- char buf[128];
- if (astro::microLightYearsToKilometers(v.length()) >=
- 86400.0 * astro::speedOfLight)
- {
- // Light travel time in years, if >= 1day
- sprintf(buf, _("Light travel time: %.4f yr "),
- v.length() * 1.0e-6);
- flash(buf, 2.0);
- }
- else
- {
- // If Light travel delay < 1 day, display in [ hr : min : sec ]
- getLightTravelDelay(v.length(), hours, mins, secs);
- if (hours == 0)
- sprintf(buf, _("Light travel time: %d min %.1f s"),
- mins, secs);
- else
- sprintf(buf, _("Light travel time: %d h %d min %.1f s")
- ,hours, mins, secs);
- flash(buf, 2.0);
- }
- }
- break;
- case '-':
- addToHistory();
- if (sim->getSelection().body() &&
- (sim->getTargetSpeed() < 0.99 *
- astro::kilometersToMicroLightYears(astro::speedOfLight)))
- {
- Vec3d v = sim->getSelection().getPosition(sim->getTime()) -
- sim->getObserver().getPosition();
- lightTravelFlag = !lightTravelFlag;
- if (lightTravelFlag)
- {
- flash(_("Light travel delay included"),2.0);
- setLightTravelDelay(v.length());
- }
- else
- {
- flash(_("Light travel delay switched off"),2.0);
- setLightTravelDelay(-v.length());
- }
- }
- else
- {
- flash(_("Light travel delay ignored"));
- }
- break;
- case ',':
- addToHistory();
- if (observer->getFOV() > MinimumFOV)
- {
- observer->setFOV(observer->getFOV() / 1.05f);
- setZoomFromFOV();
- if((renderer->getRenderFlags() & Renderer::ShowAutoMag))
- {
- setFaintestAutoMag();
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Magnitude limit: %.2f"), sim->getFaintestVisible());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- }
- break;
- case '.':
- addToHistory();
- if (observer->getFOV() < MaximumFOV)
- {
- observer->setFOV(observer->getFOV() * 1.05f);
- setZoomFromFOV();
- if((renderer->getRenderFlags() & Renderer::ShowAutoMag) != 0)
- {
- setFaintestAutoMag();
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Magnitude limit: %.2f"), sim->getFaintestVisible());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- }
- break;
- case '+':
- addToHistory();
- if (observer->getDisplayedSurface() != "")
- {
- observer->setDisplayedSurface("");
- flash(_("Using normal surface textures."));
- }
- else
- {
- observer->setDisplayedSurface("limit of knowledge");
- flash(_("Using limit of knowledge surface textures."));
- }
- break;
- case '/':
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowDiagrams);
- notifyWatchers(RenderFlagsChanged);
- break;
- case '0':
- addToHistory();
- sim->selectPlanet(-1);
- break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- addToHistory();
- if (!(modifiers & ControlKey))
- sim->selectPlanet(c - '1');
- break;
- case ';':
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowCelestialSphere);
- notifyWatchers(RenderFlagsChanged);
- break;
- case '=':
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::ConstellationLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'B':
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::StarLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'C':
- addToHistory();
- if (c == 'c')
- sim->centerSelection();
- else
- sim->centerSelectionCO();
- break;
- case 'D':
- addToHistory();
- if (config->demoScriptFile != "")
- runScript(config->demoScriptFile);
- break;
- case 'E':
- if (c == 'e')
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::GalaxyLabels);
- else
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::GlobularLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'F':
- addToHistory();
- flash(_("Follow"));
- sim->follow();
- break;
- case 'G':
- addToHistory();
- if (sim->getFrame()->getCoordinateSystem() == ObserverFrame::Universal)
- sim->follow();
- sim->gotoSelection(5.0, Vec3f(0, 1, 0), ObserverFrame::ObserverLocal);
- break;
- case 'H':
- addToHistory();
- sim->setSelection(sim->getUniverse()->getStarCatalog()->find(0));
- break;
- case 'I':
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowCloudMaps);
- notifyWatchers(RenderFlagsChanged);
- break;
- case 'J':
- addToHistory();
- sim->setTimeScale(-sim->getTimeScale());
- if (sim->getTimeScale() >= 0)
- flash(_("Time: Forward"));
- else
- flash(_("Time: Backward"));
- break;
- case 'K':
- addToHistory();
- if (abs(sim->getTimeScale()) > MinimumTimeRate)
- {
- if (c == 'k')
- sim->setTimeScale(sim->getTimeScale() / CoarseTimeScaleFactor);
- else
- sim->setTimeScale(sim->getTimeScale() / FineTimeScaleFactor);
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, "%s: " TIMERATE_PRINTF_FORMAT, _("Time rate"), sim->getTimeScale());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- break;
- case 'L':
- addToHistory();
- if (abs(sim->getTimeScale()) < MaximumTimeRate)
- {
- if (c == 'l')
- sim->setTimeScale(sim->getTimeScale() * CoarseTimeScaleFactor);
- else
- sim->setTimeScale(sim->getTimeScale() * FineTimeScaleFactor);
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, "%s: " TIMERATE_PRINTF_FORMAT, _("Time rate"), sim->getTimeScale());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- break;
- case 'M':
- if (c == 'm')
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::MoonLabels);
- else
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::MinorMoonLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'N':
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::SpacecraftLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'O':
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowOrbits);
- notifyWatchers(RenderFlagsChanged);
- break;
- case 'P':
- if (c == 'p')
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::PlanetLabels);
- else
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::DwarfPlanetLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'Q':
- sim->setTargetSpeed(-sim->getTargetSpeed());
- break;
- case 'S':
- sim->setTargetSpeed(0);
- break;
- case 'T':
- addToHistory();
- if (sim->getTrackedObject().empty())
- sim->setTrackedObject(sim->getSelection());
- else
- sim->setTrackedObject(Selection());
- break;
- case 'U':
- if (c == 'u')
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowGalaxies);
- else
- renderer->setRenderFlags(renderer->getRenderFlags() ^ Renderer::ShowGlobulars);
- notifyWatchers(RenderFlagsChanged);
- break;
- case 'V':
- setHudDetail((getHudDetail() + 1) % 3);
- break;
- case 'W':
- if (c == 'w')
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::AsteroidLabels);
- else
- renderer->setLabelMode(renderer->getLabelMode() ^ Renderer::CometLabels);
- notifyWatchers(LabelFlagsChanged);
- break;
- case 'X':
- sim->setTargetSpeed(sim->getTargetSpeed());
- break;
- case 'Y':
- flash(_("Sync Orbit"));
- addToHistory();
- sim->geosynchronousFollow();
- break;
- case ':':
- flash(_("Lock"));
- addToHistory();
- sim->phaseLock();
- break;
- case '"':
- flash(_("Chase"));
- addToHistory();
- sim->chase();
- break;
- case '[':
- if ((renderer->getRenderFlags() & Renderer::ShowAutoMag) == 0)
- {
- if (sim->getFaintestVisible() > 1.0f)
- {
- setFaintest(sim->getFaintestVisible() - 0.2f);
- notifyWatchers(FaintestChanged);
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Magnitude limit: %.2f"),sim->getFaintestVisible());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- }
- else if (renderer->getFaintestAM45deg() > 6.0f)
- {
- renderer->setFaintestAM45deg(renderer->getFaintestAM45deg() - 0.1f);
- setFaintestAutoMag();
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Auto magnitude limit at 45 degrees: %.2f"),renderer->getFaintestAM45deg());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- break;
- case '\':
- addToHistory();
- sim->setTimeScale(1.0f);
- break;
- case ']':
- if((renderer->getRenderFlags() & Renderer::ShowAutoMag) == 0)
- {
- if (sim->getFaintestVisible() < 15.0f)
- {
- setFaintest(sim->getFaintestVisible() + 0.2f);
- notifyWatchers(FaintestChanged);
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Magnitude limit: %.2f"),sim->getFaintestVisible());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- }
- else if (renderer->getFaintestAM45deg() < 12.0f)
- {
- renderer->setFaintestAM45deg(renderer->getFaintestAM45deg() + 0.1f);
- setFaintestAutoMag();
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Auto magnitude limit at 45 degrees: %.2f"),renderer->getFaintestAM45deg());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- break;
- case '`':
- showFPSCounter = !showFPSCounter;
- break;
- case '{':
- {
- if (renderer->getAmbientLightLevel() > 0.05f)
- renderer->setAmbientLightLevel(renderer->getAmbientLightLevel() - 0.05f);
- else
- renderer->setAmbientLightLevel(0.0f);
- notifyWatchers(AmbientLightChanged);
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Ambient light level: %.2f"),renderer->getAmbientLightLevel());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- break;
- case '}':
- {
- if (renderer->getAmbientLightLevel() < 0.95f)
- renderer->setAmbientLightLevel(renderer->getAmbientLightLevel() + 0.05f);
- else
- renderer->setAmbientLightLevel(1.0f);
- notifyWatchers(AmbientLightChanged);
- char buf[128];
- setlocale(LC_NUMERIC, "");
- sprintf(buf, _("Ambient light level: %.2f"),renderer->getAmbientLightLevel());
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- }
- break;
- case '(':
- {
- char buf[128];
- Galaxy::decreaseLightGain();
- setlocale(LC_NUMERIC, "");
- sprintf(buf, "%s: %3.0f %%", _("Light gain"), Galaxy::getLightGain() * 100.0f);
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- notifyWatchers(GalaxyLightGainChanged);
- }
- break;
- case ')':
- {
- char buf[128];
- Galaxy::increaseLightGain();
- setlocale(LC_NUMERIC, "");
- sprintf(buf, "%s: %3.0f %%", _("Light gain"), Galaxy::getLightGain() * 100.0f);
- setlocale(LC_NUMERIC, "C");
- flash(buf);
- notifyWatchers(GalaxyLightGainChanged);
- }
- break;
- case '~':
- showConsole = !showConsole;
- break;
- case '@':
- // TODO: 'Edit mode' should be eliminated; it can be done better
- // with a Lua script.
- editMode = !editMode;
- break;
- #ifdef USE_HDR
- case '|':
- renderer->setBloomEnabled(!renderer->getBloomEnabled());
- if (renderer->getBloomEnabled())
- flash(_("Bloom enabled"));
- else
- flash(_("Bloom disabled"));
- break;
- case '<':
- {
- char buf[64];
- renderer->decreaseBrightness();
- sprintf(buf, "%s: %+3.2f", _("Exposure"), -renderer->getBrightness());
- flash(buf);
- }
- break;
- case '>':
- {
- char buf[64];
- renderer->increaseBrightness();
- sprintf(buf, "%s: %+3.2f", _("Exposure"), -renderer->getBrightness());
- flash(buf);
- }
- break;
- #endif
- }
- }
- void CelestiaCore::getLightTravelDelay(double distance, int& hours, int& mins,
- float& secs)
- {
- // light travel time in hours
- double lt = astro::microLightYearsToKilometers(distance)/
- (3600.0 * astro::speedOfLight);
- hours = (int) lt;
- double mm = (lt - hours) * 60;
- mins = (int) mm;
- secs = (float) ((mm - mins) * 60);
- }
- void CelestiaCore::setLightTravelDelay(double distance)
- {
- // light travel time in days
- double lt = astro::microLightYearsToKilometers(distance)/
- (86400.0 * astro::speedOfLight);
- sim->setTime(sim->getTime() - lt);
- }
- bool CelestiaCore::getAltAzimuthMode() const
- {
- return altAzimuthMode;
- }
- void CelestiaCore::setAltAzimuthMode(bool enable)
- {
- altAzimuthMode = enable;
- }
- void CelestiaCore::start(double t)
- {
- if (config->initScriptFile != "")
- {
- // using the KdeAlerter in runScript would create an infinite loop,
- // break it here by resetting config->initScriptFile:
- string filename = config->initScriptFile;
- config->initScriptFile = "";
- runScript(filename);
- }
- // Set the simulation starting time to the current system time
- sim->setTime(t);
- sim->update(0.0);
- sysTime = timer->getTime();
- if (startURL != "")
- goToUrl(startURL);
- }
- void CelestiaCore::setStartURL(string url)
- {
- if (!url.substr(0,4).compare("cel:"))
- {
- startURL = url;
- config->initScriptFile = "";
- }
- else
- {
- config->initScriptFile = url;
- }
- }
- void CelestiaCore::tick()
- {
- double lastTime = sysTime;
- sysTime = timer->getTime();
- // The time step is normally driven by the system clock; however, when
- // recording a movie, we fix the time step the frame rate of the movie.
- double dt = 0.0;
- if (movieCapture != NULL && recording)
- {
- dt = 1.0 / movieCapture->getFrameRate();
- }
- else
- {
- dt = sysTime - lastTime;
- }
- // Pause script execution
- if (scriptState == ScriptPaused)
- dt = 0.0;
- currentTime += dt;
- // Mouse wheel zoom
- if (zoomMotion != 0.0f)
- {
- double span = 0.1;
- double fraction;
- if (currentTime - zoomTime >= span)
- fraction = (zoomTime + span) - (currentTime - dt);
- else
- fraction = dt / span;
- // sim->changeOrbitDistance(zoomMotion * (float) fraction);
- if (currentTime - zoomTime >= span)
- zoomMotion = 0.0f;
- }
- // Mouse wheel dolly
- if (dollyMotion != 0.0)
- {
- double span = 0.1;
- double fraction;
- if (currentTime - dollyTime >= span)
- fraction = (dollyTime + span) - (currentTime - dt);
- else
- fraction = dt / span;
- sim->changeOrbitDistance((float) (dollyMotion * fraction));
- if (currentTime - dollyTime >= span)
- dollyMotion = 0.0f;
- }
- // Keyboard dolly
- if (keysPressed[Key_Home])
- sim->changeOrbitDistance((float) (-dt * 2));
- if (keysPressed[Key_End])
- sim->changeOrbitDistance((float) (dt * 2));
- // Keyboard rotate
- Vec3d av = sim->getObserver().getAngularVelocity();
- av = av * exp(-dt * RotationDecay);
- float fov = sim->getActiveObserver()->getFOV() / stdFOV;
- Selection refObject = sim->getFrame()->getRefObject();
- // Handle arrow keys; disable them when the log console is displayed,
- // because then they're used to scroll up and down.
- if (!showConsole)
- {
- if (!altAzimuthMode)
- {
- if (keysPressed[Key_Left])
- av += Vec3d(0.0, 0.0, dt * -KeyRotationAccel);
- if (keysPressed[Key_Right])
- av += Vec3d(0.0, 0.0, dt * KeyRotationAccel);
- if (keysPressed[Key_Down])
- av += Vec3d(dt * fov * -KeyRotationAccel, 0.0, 0.0);
- if (keysPressed[Key_Up])
- av += Vec3d(dt * fov * KeyRotationAccel, 0.0, 0.0);
- }
- else
- {
- if (!refObject.empty())
- {
- Quatd orientation = sim->getObserver().getOrientation();
- Vec3d up = sim->getObserver().getPosition() - refObject.getPosition(sim->getTime());
- up.normalize();
- Vec3d v = up * (KeyRotationAccel * dt);
- v = v * (~orientation).toMatrix3();
- if (keysPressed[Key_Left])
- av -= v;
- if (keysPressed[Key_Right])
- av += v;
- if (keysPressed[Key_Down])
- av += Vec3d(dt * fov * -KeyRotationAccel, 0.0, 0.0);
- if (keysPressed[Key_Up])
- av += Vec3d(dt * fov * KeyRotationAccel, 0.0, 0.0);
- }
- }
- }
- if (keysPressed[Key_NumPad4])
- av += Vec3d(0.0, dt * fov * -KeyRotationAccel, 0.0);
- if (keysPressed[Key_NumPad6])
- av += Vec3d(0.0, dt * fov * KeyRotationAccel, 0.0);
- if (keysPressed[Key_NumPad2])
- av += Vec3d(dt * fov * -KeyRotationAccel, 0.0, 0.0);
- if (keysPressed[Key_NumPad8])
- av += Vec3d(dt * fov * KeyRotationAccel, 0.0, 0.0);
- if (keysPressed[Key_NumPad7] || joyButtonsPressed[JoyButton7])
- av += Vec3d(0.0, 0.0, dt * -KeyRotationAccel);
- if (keysPressed[Key_NumPad9] || joyButtonsPressed[JoyButton8])
- av += Vec3d(0.0, 0.0, dt * KeyRotationAccel);
- //Use Boolean to indicate if sim->setTargetSpeed() is called
- bool bSetTargetSpeed = false;
- if (joystickRotation != Vec3f(0.0f, 0.0f, 0.0f))
- {
- bSetTargetSpeed = true;
- av += (dt * KeyRotationAccel) * Vec3d(joystickRotation.x, joystickRotation.y, joystickRotation.z);
- sim->setTargetSpeed(sim->getTargetSpeed());
- }
- if (keysPressed[Key_NumPad5])
- av = av * exp(-dt * RotationBraking);
- sim->getObserver().setAngularVelocity(av);
- if (keysPressed[(int)'A'] || joyButtonsPressed[JoyButton2])
- {
- bSetTargetSpeed = true;
- if (sim->getTargetSpeed() == 0.0f)
- sim->setTargetSpeed(astro::kilometersToMicroLightYears(0.1f));
- else
- sim->setTargetSpeed(sim->getTargetSpeed() * (float) exp(dt * 3));
- }
- if (keysPressed[(int)'Z'] || joyButtonsPressed[JoyButton1])
- {
- bSetTargetSpeed = true;
- sim->setTargetSpeed(sim->getTargetSpeed() / (float) exp(dt * 3));
- }
- if (!bSetTargetSpeed && av.length() > 0.0f)
- {
- //Force observer velocity vector to align with observer direction if an observer
- //angular velocity still exists.
- sim->setTargetSpeed(sim->getTargetSpeed());
- }
- if (!refObject.empty())
- {
- Quatf q(1.0f);
- float coarseness = ComputeRotationCoarseness(*sim);
- if (shiftKeysPressed[Key_Left])
- q = q * Quatf::yrotation((float) (dt * -KeyRotationAccel * coarseness));
- if (shiftKeysPressed[Key_Right])
- q = q * Quatf::yrotation((float) (dt * KeyRotationAccel * coarseness));
- if (shiftKeysPressed[Key_Up])
- q = q * Quatf::xrotation((float) (dt * -KeyRotationAccel * coarseness));
- if (shiftKeysPressed[Key_Down])
- q = q * Quatf::xrotation((float) (dt * KeyRotationAccel * coarseness));
- sim->orbit(q);
- }
- // If there's a script running, tick it
- if (runningScript != NULL)
- {
- bool finished = runningScript->tick(dt);
- if (finished)
- cancelScript();
- }
- #ifdef CELX
- if (celxScript != NULL)
- {
- celxScript->handleTickEvent(dt);
- if (scriptState == ScriptRunning)
- {
- bool finished = celxScript->tick(dt);
- if (finished)
- cancelScript();
- }
- }
- if (luaHook != NULL)
- luaHook->callLuaHook(this, "tick", dt);
- #endif // CELX
- sim->update(dt);
- }
- void CelestiaCore::draw()
- {
- if (!viewUpdateRequired())
- return;
- viewChanged = false;
- if (views.size() == 1)
- {
- // I'm not certain that a special case for one view is required; but,
- // it's possible that there exists some broken hardware out there
- // that has to fall back to software rendering if the scissor test
- // is enable. To keep performance on this hypothetical hardware
- // reasonable in the typical single view case, we'll use this
- // scissorless special case. I'm only paranoid because I've been
- // burned by crap hardware so many times. cjl
- glViewport(0, 0, width, height);
- renderer->resize(width, height);
- sim->render(*renderer);
- }
- else
- {
- glEnable(GL_SCISSOR_TEST);
- for (list<View*>::iterator iter = views.begin();
- iter != views.end(); iter++)
- {
- View* view = *iter;
- if (view->type == View::ViewWindow)
- {
- glScissor((GLint) (view->x * width),
- (GLint) (view->y * height),
- (GLsizei) (view->width * width),
- (GLsizei) (view->height * height));
- glViewport((GLint) (view->x * width),
- (GLint) (view->y * height),
- (GLsizei) (view->width * width),
- (GLsizei) (view->height * height));
- renderer->resize((int) (view->width * width),
- (int) (view->height * height));
- sim->render(*renderer, *view->observer);
- }
- }
- glDisable(GL_SCISSOR_TEST);
- glViewport(0, 0, width, height);
- }
- renderOverlay();
- if (showConsole)
- {
- console.setFont(font);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- console.begin();
- glTranslatef(0.0f, 200.0f, 0.0f);
- console.render(ConsolePageRows);
- console.end();
- }
- if (movieCapture != NULL && recording)
- movieCapture->captureFrame();
- // Frame rate counter
- nFrames++;
- if (nFrames == 100 || sysTime - fpsCounterStartTime > 10.0)
- {
- fps = (double) nFrames / (sysTime - fpsCounterStartTime);
- nFrames = 0;
- fpsCounterStartTime = sysTime;
- }
- #if 0
- GLenum err = glGetError();
- if (err != GL_NO_ERROR)
- {
- cout << _("GL error: ") << gluErrorString(err) << 'n';
- }
- #endif
- }
- void CelestiaCore::resize(GLsizei w, GLsizei h)
- {
- if (h == 0)
- h = 1;
- glViewport(0, 0, w, h);
- if (renderer != NULL)
- renderer->resize(w, h);
- if (overlay != NULL)
- overlay->setWindowSize(w, h);
- console.setScale(w, h);
- width = w;
- height = h;
- setFOVFromZoom();
- #ifdef CELX
- if (luaHook && luaHook->callLuaHook(this,"resize", (float) w, (float) h))
- return;
- #endif
- }