pioneer/src/SystemView.cpp

692 lines
24 KiB
C++

// 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 <iomanip>
#include <sstream>
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 <typename RefType>
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<float>(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<RefType>(Projectable::PERIAPSIS, base, ref, offset + orbit->Perigeum());
AddProjected<RefType>(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<RefType>(Projectable::L4, base, ref, offset + posL4);
const vector3d posL5 = orbit->EvenSpacedPosTrajectory((1.0 / 360.0) * 300.0, tMinust0);
AddProjected<RefType>(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<const SystemBody>(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<const SystemBody>(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<const SystemBody>(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<const Ship *>(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<Body *>(Pi::player);
FrameId playerNonRotFrameId = Frame::GetFrame(PlayerBody->GetFrame())->GetNonRotFrame();
Frame *playerNonRotFrame = Frame::GetFrame(playerNonRotFrameId);
SystemBody *playerAround = playerNonRotFrame->GetSystemBody();
CalculateShipPositionAtTime(static_cast<Ship *>(Pi::player), playerOrbit, m_time, ppos);
AddProjected<Body>(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<Body>(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<Body>(Projectable::PLANNER, PlayerBody, &plannedOrbit, offset, svColor[PLANNER_ORBIT], playerAround->GetRadius());
if (std::fabs(m_time - m_game->GetTime()) > 1. && (m_time - plannerStartTime) > 0.)
AddProjected<Body>(Projectable::OBJECT, Projectable::PLANNER, PlayerBody, offset + plannedOrbit.OrbitalPosAtTime(m_time - plannerStartTime));
else
AddProjected<Body>(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<Ship *>(*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<Body>(Projectable::OBJECT, Projectable::SHIP, static_cast<Body *>((*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<Body>(Projectable::SHIP, static_cast<Body *>((*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 <typename T>
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