293 lines
9.1 KiB
C++
293 lines
9.1 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 "ObjectViewerView.h"
|
|
#include "Frame.h"
|
|
#include "GameConfig.h"
|
|
#include "Pi.h"
|
|
#include "Planet.h"
|
|
#include "Player.h"
|
|
#include "Space.h"
|
|
#include "SpaceStation.h"
|
|
#include "WorldView.h"
|
|
|
|
#include "buildopts.h"
|
|
#include "graphics/Drawables.h"
|
|
#include "graphics/Graphics.h"
|
|
#include "graphics/Light.h"
|
|
#include "graphics/Renderer.h"
|
|
#include "imgui/imgui.h"
|
|
#include "pigui/LuaPiGui.h"
|
|
#include "terrain/Terrain.h"
|
|
#include "utils.h"
|
|
|
|
#include <limits>
|
|
|
|
#if WITH_OBJECTVIEWER
|
|
|
|
ObjectViewerView::ObjectViewerView() :
|
|
PiGuiView("ObjectViewerView"),
|
|
m_targetBody(nullptr),
|
|
m_systemBody(nullptr),
|
|
m_state{}
|
|
{
|
|
SetTransparency(true);
|
|
viewingDist = 1000.0f;
|
|
m_camRot = matrix4x4d::Identity();
|
|
|
|
float size[2];
|
|
GetSizeRequested(size);
|
|
|
|
SetTransparency(true);
|
|
|
|
float znear;
|
|
float zfar;
|
|
Pi::renderer->GetNearFarRange(znear, zfar);
|
|
|
|
const float fovY = Pi::config->Float("FOVVertical");
|
|
m_cameraContext.Reset(new CameraContext(Graphics::GetScreenWidth(), Graphics::GetScreenHeight(), fovY, znear, zfar));
|
|
m_camera.reset(new Camera(m_cameraContext, Pi::renderer));
|
|
|
|
m_cameraContext->SetCameraFrame(Pi::player->GetFrame());
|
|
m_cameraContext->SetCameraPosition(Pi::player->GetInterpPosition() + vector3d(0, 0, viewingDist));
|
|
m_cameraContext->SetCameraOrient(matrix3x3d::Identity());
|
|
}
|
|
|
|
void ObjectViewerView::Draw3D()
|
|
{
|
|
PROFILE_SCOPED()
|
|
m_renderer->ClearScreen();
|
|
float znear, zfar;
|
|
m_renderer->GetNearFarRange(znear, zfar);
|
|
m_renderer->SetPerspectiveProjection(75.f, m_renderer->GetDisplayAspect(), znear, zfar);
|
|
m_renderer->SetTransform(matrix4x4f::Identity());
|
|
|
|
Graphics::Light light;
|
|
light.SetType(Graphics::Light::LIGHT_DIRECTIONAL);
|
|
|
|
const int btnState = Pi::input->MouseButtonState(SDL_BUTTON_RIGHT);
|
|
if (btnState) {
|
|
int m[2];
|
|
Pi::input->GetMouseMotion(m);
|
|
m_camRot = matrix4x4d::RotateXMatrix(-0.002 * m[1]) *
|
|
matrix4x4d::RotateYMatrix(-0.002 * m[0]) * m_camRot;
|
|
m_cameraContext->SetCameraPosition(Pi::player->GetInterpPosition() + vector3d(0, 0, viewingDist));
|
|
m_cameraContext->BeginFrame();
|
|
m_camera->Update();
|
|
}
|
|
|
|
if (m_targetBody) {
|
|
if (m_targetBody->IsType(ObjectType::STAR))
|
|
light.SetPosition(vector3f(0.f));
|
|
else {
|
|
light.SetPosition(vector3f(0.577f));
|
|
}
|
|
m_renderer->SetLights(1, &light);
|
|
|
|
m_targetBody->Render(m_renderer, m_camera.get(), vector3d(0, 0, -viewingDist), m_camRot);
|
|
|
|
// industry-standard red/green/blue XYZ axis indiactor
|
|
matrix4x4d trans = matrix4x4d::Translation(vector3d(0, 0, -viewingDist)) * m_camRot * matrix4x4d::ScaleMatrix(m_targetBody->GetClipRadius() * 2.0);
|
|
m_renderer->SetTransform(matrix4x4f(trans));
|
|
Graphics::Drawables::GetAxes3DDrawable(m_renderer)->Draw(m_renderer);
|
|
}
|
|
|
|
if (btnState) {
|
|
m_cameraContext->EndFrame();
|
|
}
|
|
}
|
|
|
|
void ObjectViewerView::OnSwitchTo()
|
|
{
|
|
// rotate X is vertical
|
|
// rotate Y is horizontal
|
|
m_camRot = matrix4x4d::RotateXMatrix(DEG2RAD(-30.0)) * matrix4x4d::RotateYMatrix(DEG2RAD(-15.0));
|
|
}
|
|
|
|
void ObjectViewerView::ReloadState()
|
|
{
|
|
if (m_targetBody->IsType(ObjectType::SPACESTATION)) {
|
|
m_systemBody = static_cast<SpaceStation *>(m_targetBody)->GetSystemBody();
|
|
} else if (m_targetBody->IsType(ObjectType::TERRAINBODY)) {
|
|
m_systemBody = static_cast<TerrainBody *>(m_targetBody)->GetSystemBody();
|
|
m_isTerrainBody = m_systemBody != nullptr;
|
|
}
|
|
|
|
if (!m_isTerrainBody)
|
|
return;
|
|
|
|
m_state.seed = m_systemBody->GetSeed();
|
|
m_state.mass = m_systemBody->GetMassAsFixed().ToDouble();
|
|
m_state.radius = m_systemBody->GetRadiusAsFixed().ToDouble();
|
|
m_state.life = m_systemBody->GetLife();
|
|
m_state.volatileGas = m_systemBody->GetVolatileGas();
|
|
m_state.volatileIces = m_systemBody->GetVolatileIces();
|
|
m_state.volatileLiquid = m_systemBody->GetVolatileLiquid();
|
|
m_state.metallicity = m_systemBody->GetMetallicity();
|
|
m_state.volcanicity = m_systemBody->GetVolcanicity();
|
|
}
|
|
|
|
void ObjectViewerView::Update()
|
|
{
|
|
if (Pi::input->KeyState(SDLK_EQUALS)) viewingDist *= 0.99f;
|
|
if (Pi::input->KeyState(SDLK_MINUS)) viewingDist *= 1.01f;
|
|
viewingDist = Clamp(viewingDist, 10.0f, 1e12f);
|
|
|
|
Body *body = Pi::player->GetNavTarget();
|
|
if (body != m_targetBody) {
|
|
m_targetBody = body;
|
|
m_isTerrainBody = false;
|
|
m_systemBody = nullptr;
|
|
|
|
if (body) {
|
|
ReloadState();
|
|
|
|
// Reset view distance for new target.
|
|
viewingDist = body->GetClipRadius() * 2.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ObjectViewerView::DrawInfoWindow()
|
|
{
|
|
std::string infoLabel = fmt::format("View dist: {} Object: {}",
|
|
format_distance(viewingDist), m_targetBody->GetLabel());
|
|
|
|
float xpos = ImGui::GetStyle().WindowPadding.x * 2;
|
|
float ypos = Graphics::GetScreenHeight() - (ImGui::GetTextLineHeightWithSpacing() * 5 + ImGui::GetFrameHeightWithSpacing());
|
|
|
|
ImGui::SetNextWindowPos({ xpos, ypos });
|
|
ImGui::SetNextWindowSize({ Graphics::GetScreenWidth() - xpos, Graphics::GetScreenHeight() - ypos });
|
|
ImGui::Begin("ObjectViewerView#Info", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration);
|
|
|
|
ImGui::TextUnformatted(infoLabel.c_str());
|
|
|
|
if (m_systemBody)
|
|
ImGui::TextUnformatted(fmt::format("SystemPath: {} {}", m_systemBody->GetName(), to_string(m_systemBody->GetPath())).c_str());
|
|
|
|
// TODO: any more information about the current object here
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
namespace ImGui {
|
|
bool DragDouble(const char *label, double *v, double v_speed = 1.0f, double v_min = 0.0f, double v_max = 0.0f, const char *format = "%.3f", double power = 1.0f)
|
|
{
|
|
return DragScalar(label, ImGuiDataType_Double, v, v_speed, &v_min, &v_max, format, power);
|
|
}
|
|
} // namespace ImGui
|
|
|
|
void ObjectViewerView::DrawControlsWindow()
|
|
{
|
|
float xpos = Graphics::GetScreenWidth() - Graphics::GetScreenWidth() / 5.0;
|
|
float ypos = ImGui::GetStyle().WindowPadding.y;
|
|
|
|
ImGui::SetNextWindowPos({ xpos, ypos });
|
|
ImGui::SetNextWindowSize({ Graphics::GetScreenWidth() - xpos, Graphics::GetScreenHeight() - ypos });
|
|
ImGui::Begin("ObjectViewerView#Controls", nullptr, ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration);
|
|
|
|
if (m_isTerrainBody) {
|
|
bool didChange = false;
|
|
uint32_t prevSeed = m_state.seed;
|
|
|
|
ImGui::TextUnformatted("Seed");
|
|
int *seed = reinterpret_cast<int32_t *>(&m_state.seed);
|
|
didChange |= ImGui::DragInt("##seed", seed);
|
|
|
|
// Seed control buttons
|
|
if (ImGui::Button("<"))
|
|
m_state.seed--;
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Random Seed"))
|
|
m_state.seed = Pi::rng.Int32();
|
|
ImGui::SameLine();
|
|
if (ImGui::Button(">"))
|
|
m_state.seed++;
|
|
|
|
if (m_state.seed != prevSeed)
|
|
didChange = true;
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
ImGui::TextUnformatted("Mass (earths):");
|
|
didChange |= ImGui::DragDouble("##mass", &m_state.mass, 0.1, 0.01, std::numeric_limits<uint32_t>::max());
|
|
|
|
ImGui::TextUnformatted("Radius (earths):");
|
|
didChange |= ImGui::DragDouble("##radius", &m_state.radius, 0.1, 0.01, 10000.0);
|
|
|
|
ImGui::TextUnformatted("Volatile gases (>= 0)");
|
|
didChange |= ImGui::DragDouble("##volatile-gas", &m_state.volatileGas, 0.01, 0.0, 1000.0);
|
|
|
|
ImGui::TextUnformatted("Volatile liquid (0-1)");
|
|
didChange |= ImGui::DragDouble("##volatile-liquid", &m_state.volatileLiquid, 0.01, 0.0, 1.0);
|
|
|
|
ImGui::TextUnformatted("Volatile ices (0-1)");
|
|
didChange |= ImGui::DragDouble("##volatile-ices", &m_state.volatileIces, 0.01, 0.0, 1.0);
|
|
|
|
ImGui::TextUnformatted("Life (0-1)");
|
|
didChange |= ImGui::DragDouble("##life", &m_state.life, 0.01, 0.0, 1.0);
|
|
|
|
ImGui::TextUnformatted("Volcanicity (0-1)");
|
|
didChange |= ImGui::DragDouble("##volcanicity", &m_state.volcanicity, 0.01, 0.0, 1.0);
|
|
|
|
ImGui::TextUnformatted("Crust metallicity (0-1)");
|
|
didChange |= ImGui::DragDouble("##metallicity", &m_state.metallicity, 0.01, 0.0, 1.0);
|
|
|
|
if (ImGui::Button("Change Planet Terrain Type"))
|
|
didChange = true;
|
|
|
|
if (didChange)
|
|
OnChangeTerrain();
|
|
}
|
|
|
|
PiGui::RunHandler(Pi::GetFrameTime(), GetViewName() + ".Controls");
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
void ObjectViewerView::DrawPiGui()
|
|
{
|
|
if (m_targetBody) {
|
|
DrawInfoWindow();
|
|
|
|
DrawControlsWindow();
|
|
}
|
|
|
|
PiGuiView::DrawPiGui();
|
|
}
|
|
|
|
static constexpr fixed dtofixed(double val, uint32_t denom = 1 << 16)
|
|
{
|
|
return fixed(denom * val, denom);
|
|
}
|
|
|
|
void ObjectViewerView::OnChangeTerrain()
|
|
{
|
|
if (!m_isTerrainBody)
|
|
return;
|
|
|
|
// XXX this is horrendous, but probably safe for the moment. all bodies,
|
|
// terrain, whatever else holds a const pointer to the same toplevel
|
|
// sbody. one day objectviewer should be far more contained and not
|
|
// actually modify the space
|
|
SystemBody *sbody = const_cast<SystemBody *>(m_systemBody);
|
|
|
|
sbody->m_seed = m_state.seed;
|
|
sbody->m_radius = dtofixed(std::abs(Clamp(m_state.radius, 0.1, 10000.0)));
|
|
sbody->m_mass = dtofixed(std::abs(m_state.mass));
|
|
sbody->m_metallicity = dtofixed(std::abs(m_state.metallicity));
|
|
sbody->m_volatileGas = dtofixed(std::abs(m_state.volatileGas));
|
|
sbody->m_volatileLiquid = dtofixed(std::abs(m_state.volatileLiquid));
|
|
sbody->m_volatileIces = dtofixed(std::abs(m_state.volatileIces));
|
|
sbody->m_volcanicity = dtofixed(std::abs(m_state.volcanicity));
|
|
sbody->m_life = dtofixed(std::abs(m_state.life));
|
|
|
|
// force reload
|
|
TerrainBody::OnChangeDetailLevel();
|
|
ReloadState();
|
|
}
|
|
|
|
#endif
|