// Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt #include "graphics/Graphics.h" #include "pigui/LuaPiGui.h" #include "SystemView.h" #include "AnimationCurves.h" #include "Background.h" #include "Game.h" #include "GameLog.h" #include "Input.h" #include "Lang.h" #include "Pi.h" #include "Player.h" #include "SectorView.h" #include "Space.h" #include "StringF.h" #include "galaxy/Galaxy.h" #include "galaxy/StarSystem.h" #include "galaxy/SystemPath.h" #include "graphics/Material.h" #include "graphics/Renderer.h" #include "graphics/TextureBuilder.h" #include "lua/LuaObject.h" #include "lua/LuaTable.h" #include #include using namespace Graphics; const double SystemView::PICK_OBJECT_RECT_SIZE = 12.0; const Uint16 SystemView::N_VERTICES_MAX = 100; static const float MIN_ZOOM = 1e-30f; // Just to avoid having 0 static const float MAX_ZOOM = 1e30f; static const float ZOOM_IN_SPEED = 3; static const float ZOOM_OUT_SPEED = 3; static const float WHEEL_SENSITIVITY = .1f; // Should be a variable in user settings. static const double DEFAULT_VIEW_DISTANCE = 10.0; static const int MAX_TRANSITION_FRAMES = 60; void SystemView::InputBindings::RegisterBindings() { mapViewPitch = AddAxis("BindMapViewPitch"); mapViewYaw = AddAxis("BindMapViewYaw"); mapViewZoom = AddAxis("BindMapViewZoom"); } SystemView::SystemView(Game *game) : PiGuiView("system-view"), m_input(Pi::input), m_game(game), m_showL4L5(LAG_OFF), m_shipDrawing(OFF), m_gridDrawing(GridDrawing::OFF), m_trans(0.0), m_transTo(0.0) { m_rot_y = 0; m_rot_x = 50; m_zoom = 1.0f / float(AU); SetTransparency(true); m_input.RegisterBindings(); Graphics::RenderStateDesc rsd; m_lineState = Pi::renderer->CreateRenderState(rsd); //m_renderer not set yet m_realtime = true; m_unexplored = true; m_onMouseWheelCon = Pi::input->onMouseWheel.connect(sigc::mem_fun(this, &SystemView::MouseWheel)); ResetViewpoint(); RefreshShips(); m_planner = Pi::planner; m_orbitVts.reset(new vector3f[N_VERTICES_MAX]); m_orbitColors.reset(new Color[N_VERTICES_MAX]); } SystemView::~SystemView() { m_contacts.clear(); m_onMouseWheelCon.disconnect(); } void SystemView::AccelerateTime(float step) { m_realtime = false; m_timeStep = step; } void SystemView::SetRealTime() { m_realtime = true; } void SystemView::ResetViewpoint() { m_selectedObject.type = Projectable::NONE; m_rot_y_to = 0; m_rot_x_to = 50; m_zoomTo = 1.0f / float(AU); m_timeStep = 1.0f; m_time = m_game->GetTime(); m_transTo *= 0.0; m_animateTransition = MAX_TRANSITION_FRAMES; } template void SystemView::PutOrbit(Projectable::bases base, RefType *ref, const Orbit *orbit, const vector3d &offset, const Color &color, const double planetRadius, const bool showLagrange) { double ecc = orbit->GetEccentricity(); double timeshift = ecc > 0.6 ? 0.0 : 0.5; double maxT = 1.; unsigned short num_vertices = 0; for (unsigned short i = 0; i < N_VERTICES_MAX; ++i) { const double t = (double(i) + timeshift) / double(N_VERTICES_MAX); const vector3d pos = orbit->EvenSpacedPosTrajectory(t); if (pos.Length() < planetRadius) { maxT = t; break; } } static const float startTrailPercent = 0.85; static const float fadedColorParameter = 0.8; Uint16 fadingColors = 0; const double tMinust0 = GetOrbitTime(m_time, ref); for (unsigned short i = 0; i < N_VERTICES_MAX; ++i) { const double t = (double(i) + timeshift) / double(N_VERTICES_MAX) * maxT; if (fadingColors == 0 && t >= startTrailPercent * maxT) fadingColors = i; const vector3d pos = orbit->EvenSpacedPosTrajectory(t, tMinust0); m_orbitVts[i] = vector3f(offset + pos); ++num_vertices; if (pos.Length() < planetRadius) break; } const Color fadedColor = color * fadedColorParameter; std::fill_n(m_orbitColors.get(), num_vertices, fadedColor); const Uint16 trailLength = num_vertices - fadingColors; for (Uint16 currentColor = 0; currentColor < trailLength; ++currentColor) { float scalingParameter = fadedColorParameter + static_cast(currentColor) / trailLength * (1.f - fadedColorParameter); m_orbitColors[currentColor + fadingColors] = color * scalingParameter; } if (num_vertices > 1) { m_orbits.SetData(num_vertices, m_orbitVts.get(), m_orbitColors.get()); //close the loop for thin ellipses if (maxT < 1. || ecc > 1.0 || ecc < 0.6) { m_orbits.Draw(m_renderer, m_lineState, LINE_STRIP); } else { m_orbits.Draw(m_renderer, m_lineState, LINE_LOOP); } } AddProjected(Projectable::PERIAPSIS, base, ref, offset + orbit->Perigeum()); AddProjected(Projectable::APOAPSIS, base, ref, offset + orbit->Apogeum()); if (showLagrange && m_showL4L5 != LAG_OFF) { const vector3d posL4 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 60.0, tMinust0); AddProjected(Projectable::L4, base, ref, offset + posL4); const vector3d posL5 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 300.0, tMinust0); AddProjected(Projectable::L5, base, ref, offset + posL5); } } // returns the position of the ground spaceport relative to the center of the planet at the specified time static vector3d position_of_surface_starport_relative_to_parent(const SystemBody *starport, double time) { const SystemBody *parent = starport->GetParent(); // planet axis tilt return matrix3x3d::RotateX(parent->GetAxialTilt()) * // the angle the planet has turned since the beginning of time matrix3x3d::RotateY(-2 * M_PI / parent->GetRotationPeriod() * time + parent->GetRotationPhaseAtStart()) * // the original coordinates of the starport are saved as a 3x3 matrix, starport->GetOrbit().GetPlane() * // to get the direction to the station, you need to multiply them by 0.0, 1.0, 0.0 vector3d(0.0, 1.0, 0.0) * // we need the distance to the center of the planet (Pi::game->IsNormalSpace() && Pi::game->GetSpace()->GetStarSystem()->GetPath().IsSameSystem(Pi::game->GetSectorView()->GetSelected()) ? // if we look at the current system, the relief is known, we take the height from the physical body Pi::game->GetSpace()->FindBodyForPath(&(starport->GetPath()))->GetPosition().Length() : // if the remote system - take the radius of the planet parent->GetRadius()); } void SystemView::PutBody(const SystemBody *b, const vector3d &offset, const matrix4x4f &trans) { if (b->GetType() == SystemBody::TYPE_STARPORT_SURFACE) return; if (b->GetType() != SystemBody::TYPE_GRAVPOINT) { if (!m_bodyIcon) { Graphics::RenderStateDesc rsd; auto solidState = m_renderer->CreateRenderState(rsd); m_bodyIcon.reset(new Graphics::Drawables::Disk(m_renderer, solidState, svColor[SYSTEMBODY], 1.0f)); } const double radius = b->GetRadius(); matrix4x4f invRot = trans; invRot.ClearToRotOnly(); invRot.Renormalize(); invRot = invRot.Inverse(); matrix4x4f bodyTrans = trans; bodyTrans.Translate(vector3f(offset)); bodyTrans.Scale(radius); m_renderer->SetTransform(bodyTrans * invRot); m_bodyIcon->Draw(m_renderer); m_renderer->SetTransform(trans); AddProjected(Projectable::OBJECT, Projectable::SYSTEMBODY, b, offset); } // display all child bodies and their orbits if (b->HasChildren()) { for (const SystemBody *kid : b->GetChildren()) { if (kid->GetType() == SystemBody::TYPE_STARPORT_SURFACE) { AddProjected(Projectable::OBJECT, Projectable::SYSTEMBODY, kid, position_of_surface_starport_relative_to_parent(kid, m_time) + offset); continue; } if (is_zero_general(kid->GetOrbit().GetSemiMajorAxis())) continue; const double axisZoom = kid->GetOrbit().GetSemiMajorAxis(); //semimajor axis radius should be at least 1% of screen width to show the orbit if (ProjectedSize(axisZoom, offset) > 0.01) { const SystemBody::BodySuperType bst = kid->GetSuperType(); const bool showLagrange = (bst == SystemBody::SUPERTYPE_ROCKY_PLANET || bst == SystemBody::SUPERTYPE_GAS_GIANT); PutOrbit(Projectable::SYSTEMBODY, kid, &(kid->GetOrbit()), offset, svColor[SYSTEMBODY_ORBIT], 0.0, showLagrange); } // not using current time yet const vector3d pos = kid->GetOrbit().OrbitalPosAtTime(m_time); PutBody(kid, offset + pos, trans); } } } void SystemView::GetTransformTo(const SystemBody *b, vector3d &pos) { const SystemBody *parent = b->GetParent(); if (parent) { GetTransformTo(parent, pos); if (b->GetType() == SystemBody::TYPE_STARPORT_SURFACE) pos -= position_of_surface_starport_relative_to_parent(b, m_time); else pos -= b->GetOrbit().OrbitalPosAtTime(m_time); } } void SystemView::GetTransformTo(Projectable &p, vector3d &pos) { if (m_selectedObject.type == Projectable::NONE) { // notning selected pos *= 0.0; return; } // accept only real objects (no orbit icons or lagrange points) assert(p.type == Projectable::OBJECT); pos = vector3d(0., 0., 0.); if (p.base == Projectable::SYSTEMBODY) GetTransformTo(p.ref.sbody, pos); else if (p.ref.body->GetType() == ObjectType::SHIP || p.ref.body->GetType() == ObjectType::PLAYER) { const Ship *s = static_cast(p.ref.body); CalculateShipPositionAtTime(s, s->ComputeOrbit(), m_time, pos); pos = -pos; // sometimes ships can dissapear from world (i.e. docking / undocking) if (std::isnan(pos.x)) { // failsafe: calculate parent systembody instead pos = vector3d(0., 0., 0.); GetTransformTo(Frame::GetFrame(Frame::GetFrame(Pi::player->GetFrame())->GetNonRotFrame())->GetSystemBody(), pos); } } } void SystemView::CalculateShipPositionAtTime(const Ship *s, Orbit o, double t, vector3d &pos) { pos = vector3d(0., 0., 0.); FrameId shipFrameId = s->GetFrame(); FrameId shipNonRotFrameId = Frame::GetFrame(shipFrameId)->GetNonRotFrame(); // if the ship is in a rotating frame, we will rotate it with the frame if (Frame::GetFrame(shipFrameId)->IsRotFrame()) { vector3d rpos(0.0); Frame *rotframe = Frame::GetFrame(shipFrameId); if (t == m_game->GetTime()) { pos = s->GetPositionRelTo(m_game->GetSpace()->GetRootFrame()); return; } else rpos = s->GetPositionRelTo(shipNonRotFrameId) * rotframe->GetOrient() * matrix3x3d::RotateY(rotframe->GetAngSpeed() * (t - m_game->GetTime())) * rotframe->GetOrient().Transpose(); vector3d fpos(0.0); CalculateFramePositionAtTime(shipNonRotFrameId, t, fpos); pos += fpos + rpos; } else { vector3d fpos(0.0); CalculateFramePositionAtTime(shipNonRotFrameId, t, fpos); pos += (fpos + o.OrbitalPosAtTime(t - m_game->GetTime())); } } //frame must be nonrotating void SystemView::CalculateFramePositionAtTime(FrameId frameId, double t, vector3d &pos) { if (frameId == m_game->GetSpace()->GetRootFrame()) pos = vector3d(0., 0., 0.); else { Frame *frame = Frame::GetFrame(frameId); CalculateFramePositionAtTime(frame->GetParent(), t, pos); pos += frame->GetSystemBody()->GetOrbit().OrbitalPosAtTime(t); } } void SystemView::Draw3D() { PROFILE_SCOPED() m_renderer->ClearScreen(); m_projected.clear(); SystemPath path = m_game->GetSectorView()->GetSelected().SystemOnly(); if (m_system) { if (m_system->GetUnexplored() != m_unexplored || !m_system->GetPath().IsSameSystem(path)) { m_system.Reset(); ResetViewpoint(); } } if (m_realtime) { m_time = m_game->GetTime(); } else { m_time += m_timeStep * Pi::GetFrameTime(); } std::string t = Lang::TIME_POINT + format_date(m_time); if (!m_system) { m_system = m_game->GetGalaxy()->GetStarSystem(path); m_unexplored = m_system->GetUnexplored(); } // Set up the perspective projection for the background stars m_renderer->SetPerspectiveProjection(CAMERA_FOV, m_renderer->GetDisplayAspect(), 1.f, 1500.f); matrix4x4d trans2bg = matrix4x4d::Identity(); trans2bg.RotateX(DEG2RAD(-m_rot_x)); trans2bg.RotateY(DEG2RAD(-m_rot_y)); auto *background = m_game->GetSpace()->GetBackground(); // Background is rotated around (0,0,0) and drawn background->SetIntensity(0.6); if (!m_game->IsNormalSpace() || !m_game->GetSpace()->GetStarSystem()->GetPath().IsSameSystem(path)) { Uint32 cachedFlags = background->GetDrawFlags(); background->SetDrawFlags(Background::Container::DRAW_SKYBOX); background->Draw(trans2bg); background->SetDrawFlags(cachedFlags); } else { background->Draw(trans2bg); } m_renderer->ClearDepthBuffer(); // We need to adjust the "far" cutoff plane, so that at high magnifications you can see // distant objects in the background. m_renderer->SetPerspectiveProjection(CAMERA_FOV, m_renderer->GetDisplayAspect(), 1.f, 1000.f * m_zoom * float(AU) + DEFAULT_VIEW_DISTANCE * 2); //TODO add reserve // The matrix is shifted from the (0,0,0) by DEFAULT_VIEW_DISTANCE // and then rotated (around 0,0,0) and scaled by m_zoom, shift doesn't scale. // m_zoom default value is 1/AU. // { src/gameconsts.h:static const double AU = 149598000000.0; // m } // The coordinates of the objects are given in meters; they are multiplied by m_zoom, // therefore dy default, 1.0 AU (in meters) in the coordinate turns into 1.0 in camera space. // Since the *shift doesn't scale*, it always equals to DEFAULT_VIEW_DISTANCE, // in camera space. // So, the "apparent" view distance, is DEFAULT_VIEW_DISTANCE / m_zoom * AU (AU) // Therefore the default "apparent" view distance is DEFAULT_VIEW_DISTANCE, in AU // When we change m_zoom, we actually change the "apparent" view distance, because // the coordinates of the objects are scaled, but the shift is not. m_cameraSpace = matrix4x4f::Identity(); m_cameraSpace.Translate(0, 0, -DEFAULT_VIEW_DISTANCE); m_cameraSpace.Rotate(DEG2RAD(m_rot_x), 1, 0, 0); m_cameraSpace.Rotate(DEG2RAD(m_rot_y), 0, 1, 0); m_cameraSpace.Scale(m_zoom); m_renderer->SetTransform(m_cameraSpace); // smooth transition animation if (m_animateTransition) { // since the object being approached can move, we need to compensate for its movement // making an imprint of the old value (from previous frame) m_trans -= m_transTo; // calculate the new value GetTransformTo(m_selectedObject, m_transTo); // now the difference between the new and the old value is added to m_trans m_trans += m_transTo; const float ft = Pi::GetFrameTime(); m_animateTransition--; AnimationCurves::Approach(m_trans.x, m_transTo.x, ft); AnimationCurves::Approach(m_trans.y, m_transTo.y, ft); AnimationCurves::Approach(m_trans.z, m_transTo.z, ft); } else { GetTransformTo(m_selectedObject, m_trans); } vector3d pos = m_trans; // glLineWidth(2); if (!m_system->GetUnexplored() && m_system->GetRootBody()) { // all systembodies draws here PutBody(m_system->GetRootBody().Get(), pos, m_cameraSpace); } // glLineWidth(1); if (m_game->IsNormalSpace() && m_game->GetSpace()->GetStarSystem()->GetPath().IsSameSystem(m_game->GetSectorView()->GetSelected())) { // draw ships if (m_shipDrawing != OFF) { DrawShips(m_time, pos); } // draw player and planner vector3d ppos(0.0); Orbit playerOrbit = Pi::player->ComputeOrbit(); Body *PlayerBody = static_cast(Pi::player); FrameId playerNonRotFrameId = Frame::GetFrame(PlayerBody->GetFrame())->GetNonRotFrame(); Frame *playerNonRotFrame = Frame::GetFrame(playerNonRotFrameId); SystemBody *playerAround = playerNonRotFrame->GetSystemBody(); CalculateShipPositionAtTime(static_cast(Pi::player), playerOrbit, m_time, ppos); AddProjected(Projectable::OBJECT, Projectable::PLAYER, PlayerBody, ppos + pos); vector3d offset(0.0); CalculateFramePositionAtTime(playerNonRotFrameId, m_time, offset); offset = offset + pos; if (Pi::player->GetFlightState() == Ship::FlightState::FLYING) { PutOrbit(Projectable::PLAYER, PlayerBody, &playerOrbit, offset, svColor[PLAYER_ORBIT], playerAround->GetRadius()); const double plannerStartTime = m_planner->GetStartTime(); if (!m_planner->GetPosition().ExactlyEqual(vector3d(0, 0, 0))) { Orbit plannedOrbit = Orbit::FromBodyState(m_planner->GetPosition(), m_planner->GetVel(), playerAround->GetMass()); PutOrbit(Projectable::PLANNER, PlayerBody, &plannedOrbit, offset, svColor[PLANNER_ORBIT], playerAround->GetRadius()); if (std::fabs(m_time - m_game->GetTime()) > 1. && (m_time - plannerStartTime) > 0.) AddProjected(Projectable::OBJECT, Projectable::PLANNER, PlayerBody, offset + plannedOrbit.OrbitalPosAtTime(m_time - plannerStartTime)); else AddProjected(Projectable::OBJECT, Projectable::PLANNER, PlayerBody, offset + m_planner->GetPosition()); } } } if (m_gridDrawing != GridDrawing::OFF) { DrawGrid(); } } void SystemView::Update() { const float ft = Pi::GetFrameTime(); // TODO: add "true" lower/upper bounds to m_zoomTo / m_zoom m_zoomTo = Clamp(m_zoomTo, MIN_ZOOM, MAX_ZOOM); m_zoom = Clamp(m_zoom, MIN_ZOOM, MAX_ZOOM); // Since m_zoom changes over multiple orders of magnitude, any fixed linear factor will not be appropriate // at some of them. AnimationCurves::Approach(m_zoom, m_zoomTo, ft, 10.f, m_zoomTo / 60.f); AnimationCurves::Approach(m_rot_x, m_rot_x_to, ft); AnimationCurves::Approach(m_rot_y, m_rot_y_to, ft); // to capture mouse when button was pressed and release when released if (Pi::input->MouseButtonState(SDL_BUTTON_MIDDLE) != m_rotateWithMouseButton) { m_rotateWithMouseButton = !m_rotateWithMouseButton; Pi::input->SetCapturingMouse(m_rotateWithMouseButton); } if (m_rotateWithMouseButton || m_rotateView) { int motion[2]; Pi::input->GetMouseMotion(motion); m_rot_x_to += motion[1] * 20 * ft; m_rot_y_to += motion[0] * 20 * ft; } else if (m_zoomView) { Pi::input->SetCapturingMouse(true); int motion[2]; Pi::input->GetMouseMotion(motion); m_zoomTo *= pow(ZOOM_IN_SPEED * 0.003 + 1, -motion[1]); } // camera control signals from devices, sent to the SectorView if (m_input.mapViewZoom->IsActive()) m_zoomTo *= pow(ZOOM_IN_SPEED * 0.006 + 1, m_input.mapViewZoom->GetValue()); if (m_input.mapViewYaw->IsActive()) m_rot_y_to += m_input.mapViewYaw->GetValue() * ft * 60; if (m_input.mapViewPitch->IsActive()) m_rot_x_to += m_input.mapViewPitch->GetValue() * ft * 60; m_rot_x_to = Clamp(m_rot_x_to, -80.0f, 80.0f); if (m_shipDrawing != OFF) { RefreshShips(); // if we are attached to the ship, check if we not deleted it in the previous frame if (m_selectedObject.type != Projectable::NONE && m_selectedObject.base == Projectable::SHIP) { auto bs = m_game->GetSpace()->GetBodies(); if (std::find(bs.begin(), bs.end(), m_selectedObject.ref.body) == bs.end()) ResetViewpoint(); } } } void SystemView::MouseWheel(bool up) { if (this == Pi::GetView()) { if (!up) m_zoomTo *= 1 / ((ZOOM_OUT_SPEED - 1) * WHEEL_SENSITIVITY + 1) / Pi::GetMoveSpeedShiftModifier(); else m_zoomTo *= ((ZOOM_IN_SPEED - 1) * WHEEL_SENSITIVITY + 1) * Pi::GetMoveSpeedShiftModifier(); } } void SystemView::RefreshShips(void) { m_contacts.clear(); auto bs = m_game->GetSpace()->GetBodies(); for (auto s = bs.begin(); s != bs.end(); s++) { if ((*s) != Pi::player && (*s)->GetType() == ObjectType::SHIP) { const auto c = static_cast(*s); m_contacts.push_back(std::make_pair(c, c->ComputeOrbit())); } } } void SystemView::DrawShips(const double t, const vector3d &offset) { // offset - translate vector to selected object, scaled to camera scale for (auto s = m_contacts.begin(); s != m_contacts.end(); s++) { vector3d pos(0.0); CalculateShipPositionAtTime((*s).first, (*s).second, t, pos); pos = pos + offset; //draw highlighted orbit for selected ship const bool isSelected = m_selectedObject.type == Projectable::OBJECT && m_selectedObject.base != Projectable::SYSTEMBODY && m_selectedObject.ref.body == (*s).first; AddProjected(Projectable::OBJECT, Projectable::SHIP, static_cast((*s).first), pos); if (m_shipDrawing == ORBITS && (*s).first->GetFlightState() == Ship::FlightState::FLYING) { vector3d framepos(0.0); CalculateFramePositionAtTime((*s).first->GetFrame(), m_time, framepos); PutOrbit(Projectable::SHIP, static_cast((*s).first), &(*s).second, offset + framepos, isSelected ? svColor[SELECTED_SHIP_ORBIT] : svColor[SHIP_ORBIT], 0); } } } void SystemView::DrawGrid() { // calculate lines for this system: double diameter = std::floor(m_system->GetRootBody()->GetMaxChildOrbitalDistance() * 1.2 / AU); m_grid_lines = int(diameter) + 1; m_lineVerts.reset(new Graphics::VertexArray(Graphics::ATTRIB_POSITION, m_grid_lines * 4 + (m_gridDrawing == GridDrawing::GRID_AND_LEGS ? m_projected.size() * 2 : 0))); float zoom = float(AU); vector3d pos = m_trans; for (int i = -m_grid_lines; i < m_grid_lines + 1; i++) { float z = float(i) * zoom; m_lineVerts->Add(vector3f(-m_grid_lines * zoom, 0.0f, z) + vector3f(pos), svColor[GRID]); m_lineVerts->Add(vector3f(+m_grid_lines * zoom, 0.0f, z) + vector3f(pos), svColor[GRID]); } for (int i = -m_grid_lines; i < m_grid_lines + 1; i++) { float x = float(i) * zoom; m_lineVerts->Add(vector3f(x, 0.0f, -m_grid_lines * zoom) + vector3f(pos), svColor[GRID]); m_lineVerts->Add(vector3f(x, 0.0f, +m_grid_lines * zoom) + vector3f(pos), svColor[GRID]); } if (m_gridDrawing == GridDrawing::GRID_AND_LEGS) for (Projectable &p : m_projected) { vector3d offset(p.worldpos); offset.y = m_trans.y; m_lineVerts->Add(vector3f(p.worldpos), svColor[GRID_LEG] * 0.5); m_lineVerts->Add(vector3f(offset), svColor[GRID_LEG] * 0.5); } m_lines.SetData(m_lineVerts->GetNumVerts(), &m_lineVerts->position[0], &m_lineVerts->diffuse[0]); m_lines.Draw(Pi::renderer, m_lineState); } template void SystemView::AddProjected(Projectable::types type, Projectable::bases base, T *ref, const vector3d &worldpos) { vector3d pos = Graphics::ProjectToScreen(m_renderer, worldpos); if (pos.z > 0.0) return; // reject back-projected objects pos.y = m_renderer->GetViewport().h - pos.y; Projectable p(type, base, ref); p.screenpos = pos; p.worldpos = worldpos; m_projected.push_back(p); } void SystemView::SetVisibility(std::string param) { if (param == "RESET_VIEW") ResetViewpoint(); else if (param == "GRID_OFF") m_gridDrawing = GridDrawing::OFF; else if (param == "GRID_ON") m_gridDrawing = GridDrawing::GRID; else if (param == "GRID_AND_LEGS") m_gridDrawing = GridDrawing::GRID_AND_LEGS; else if (param == "LAG_OFF") m_showL4L5 = LAG_OFF; else if (param == "LAG_ICON") m_showL4L5 = LAG_ICON; else if (param == "LAG_ICONTEXT") m_showL4L5 = LAG_ICONTEXT; else if (param == "SHIPS_OFF") { m_shipDrawing = OFF; // if we are attached to the ship, reset view, since the ship was hidden if (m_selectedObject.type != Projectable::NONE && m_selectedObject.base == Projectable::SHIP) ResetViewpoint(); } else if (param == "SHIPS_ON") m_shipDrawing = BOXES; else if (param == "SHIPS_ORBITS") m_shipDrawing = ORBITS; else Output("Unknown visibility: %s\n", param.c_str()); } void SystemView::SetZoomMode(bool enable) { if (enable != m_zoomView) { Pi::input->SetCapturingMouse(enable); m_zoomView = enable; if (m_zoomView) m_rotateView = false; } } void SystemView::SetRotateMode(bool enable) { if (enable != m_rotateView) { Pi::input->SetCapturingMouse(enable); m_rotateView = enable; if (m_rotateView) m_zoomView = false; } } Projectable *SystemView::GetSelectedObject() { return &m_selectedObject; } void SystemView::SetSelectedObject(Projectable::types type, Projectable::bases base, SystemBody *sb) { m_selectedObject.type = type; m_selectedObject.base = base; m_selectedObject.ref.sbody = sb; // we will immediately determine the coordinates of the selected body so that // there is a correct starting point of the transition animation, otherwise // there may be an unwanted shift in the next frame GetTransformTo(m_selectedObject, m_transTo); m_animateTransition = MAX_TRANSITION_FRAMES; } void SystemView::SetSelectedObject(Projectable::types type, Projectable::bases base, Body *b) { m_selectedObject.type = type; m_selectedObject.base = base; m_selectedObject.ref.body = b; // we will immediately determine the coordinates of the selected body so that // there is a correct starting point of the transition animation, otherwise // there may be an unwanted shift in the next frame GetTransformTo(m_selectedObject, m_transTo); m_animateTransition = MAX_TRANSITION_FRAMES; } double SystemView::ProjectedSize(double size, vector3d pos) { matrix4x4d dtrans = matrix4x4d(m_cameraSpace); pos = dtrans * pos; //position in camera space to know distance double result = size / pos.Length() / CAMERA_FOV_RADIANS; return result; } double SystemView::GetOrbitTime(double t, const SystemBody *b) { return t; } double SystemView::GetOrbitTime(double t, const Body *b) { return t - m_game->GetTime(); } void SystemView::OnSwitchFrom() { m_projected.clear(); } // because ships from the previous system may remain after last update