17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 18:14:55 +01:00
Files
maszyna/launcher/scenery_wizard.cpp

217 lines
8.2 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "launcher/scenery_wizard.h"
#include "application/application.h"
#include "editor/editorFormat.hpp"
#include "editor/editorGeoMap.hpp"
#include "editor/editorOrthophoto.hpp"
#include "editor/editorSettings.hpp"
#include "utilities/Globals.h"
#include "utilities/Logs.h"
#include "utilities/translation.h"
#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdio>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <sstream>
namespace
{
bool valid_name(std::string const &Name)
{
return false == Name.empty() && std::all_of(Name.begin(), Name.end(), [](char const Character) { return (Character >= 'a' && Character <= 'z') || (Character >= '0' && Character <= '9') || Character == '_' || Character == '-'; });
}
} // namespace
ui::scenerywizard_panel::scenerywizard_panel() : ui_panel(STR("New scenery"), false) {}
ui::scenerywizard_panel::~scenerywizard_panel() = default;
void ui::scenerywizard_panel::render_contents()
{
auto const available{ImGui::GetContentRegionAvail()};
auto const form{360.f * Global.ui_scale};
glm::vec2 const map{std::max(200.f, available.x - form - ImGui::GetStyle().ItemSpacing.x), std::max(200.f, available.y)};
ImGui::BeginChild("##wizardmap", ImVec2(map.x, map.y), true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
if (m_map.render(map - glm::vec2{16.f}))
pick(m_map.point());
ImGui::EndChild();
ImGui::SameLine();
ImGui::BeginChild("##wizardform", ImVec2(0.f, map.y), true);
render_form();
ImGui::EndChild();
}
void ui::scenerywizard_panel::pick(glm::dvec2 const &Point)
{
m_map.pick(Point);
auto const degrees{editor_geo::to_degrees(Point)};
std::snprintf(m_latlon, sizeof(m_latlon), "%.6f, %.6f", degrees.x, degrees.y);
}
void ui::scenerywizard_panel::render_form()
{
ImGui::TextUnformatted(STR_C("New scenery"));
ImGui::Separator();
if (ImGui::RadioButton(STR_C("Realistic"), m_realistic))
m_realistic = true;
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("A real place: the centre is picked on the map, the editor opens with the orthophoto under it, seen from above"));
ImGui::SameLine();
if (ImGui::RadioButton(STR_C("Fictional"), false == m_realistic))
m_realistic = false;
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("No place on the map, no orthophoto: an empty plane seen from above"));
ImGui::Spacing();
ImGui::SetNextItemWidth(-1.f);
ImGui::InputTextWithHint("##name", STR_C("file name, e.g. my_line"), m_filename, sizeof(m_filename), ImGuiInputTextFlags_CharsNoBlank);
std::string name{m_filename};
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char const Character) { return static_cast<char>(std::tolower(Character)); });
auto const path{Global.asCurrentSceneryPath + name + ".scn"};
auto const named{valid_name(name)};
auto const exists{named && std::filesystem::exists(path)};
if (name.empty())
ImGui::TextDisabled("%s", STR_C("scenery/<name>.scn"));
else if (false == named)
ImGui::TextColored(ImVec4(1.f, 0.45f, 0.35f, 1.f), "%s", STR_C("Lower case letters, digits, _ and - only"));
else if (exists)
ImGui::TextColored(ImVec4(1.f, 0.45f, 0.35f, 1.f), STR_C("%s exists already"), path.c_str());
else
ImGui::TextDisabled("%s", path.c_str());
ImGui::SetNextItemWidth(-1.f);
ImGui::InputTextWithHint("##title", STR_C("title, written in the file"), m_title, sizeof(m_title));
ImGui::Spacing();
auto const placed{m_map.picked() || false == m_realistic};
auto const ready{named && false == exists && placed};
if (false == ready)
{
ImGui::TextDisabled("%s", placed ? STR_C("Give the file a name") : STR_C("Click the centre on the map"));
if (m_realistic && ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("The wheel zooms, dragging moves the map. A click sets the centre of the scenery, its point 0 0 0"));
}
if (ImGui::Button(STR_C("Create and open in the editor"), ImVec2(-1.f, 0.f)) && ready)
create_scenery();
if (false == m_status.empty())
ImGui::TextWrapped("%s", m_status.c_str());
ImGui::Spacing();
if (ImGui::TreeNode(STR_C("More settings")))
{
ImGui::BeginDisabled(false == m_realistic);
ImGui::TextUnformatted(STR_C("Centre of the scenery, PUWG 1992"));
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("PUWG 1992: the coordinate system of the maps of Poland, in km"));
double east{m_map.point().x / 1000.0};
double north{m_map.point().y / 1000.0};
ImGui::SetNextItemWidth(130.f);
auto changed{ImGui::InputDouble(STR_C("E, km##east"), &east, 0.0, 0.0, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue)};
ImGui::SetNextItemWidth(130.f);
changed |= ImGui::InputDouble(STR_C("N, km##north"), &north, 0.0, 0.0, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue);
if (changed)
{
pick({east * 1000.0, north * 1000.0});
m_map.show(m_map.point(), 1000.0);
}
ImGui::SetNextItemWidth(-90.f);
auto const entered{ImGui::InputTextWithHint("##latlon", STR_C("latitude, longitude"), m_latlon, sizeof(m_latlon), ImGuiInputTextFlags_EnterReturnsTrue)};
ImGui::SameLine();
if (ImGui::Button(STR_C("Show")) || entered)
{
std::string text{m_latlon};
std::replace(text.begin(), text.end(), ',', ' ');
std::istringstream words(text);
double latitude{0.0}, longitude{0.0};
if (words >> latitude >> longitude && latitude > 45.0 && latitude < 58.0 && longitude > 10.0 && longitude < 28.0)
{
pick(editor_geo::to_puwg(latitude, longitude));
m_map.show(m_map.point());
m_status.clear();
}
else
m_status = STR("Give the latitude and the longitude in degrees, e.g. 52.2297, 21.0122");
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("Degrees, as given by the online maps; the map moves there"));
if (m_map.picked())
{
auto const degrees{editor_geo::to_degrees(m_map.point())};
ImGui::TextDisabled(STR_C("%.5f N, %.5f E"), degrees.x, degrees.y);
}
ImGui::Spacing();
ImGui::TextWrapped("%s", STR_C("The scenery keeps the centre as its geographic reference (//$g PUWG1992): the orthophoto of the editor lies under it, in place."));
ImGui::EndDisabled();
ImGui::TreePop();
}
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled));
ImGui::TextWrapped("%s", STR_C("Map: (c) OpenStreetMap contributors, served by geoportal.gov.pl"));
ImGui::PopStyleColor();
}
bool ui::scenerywizard_panel::create_scenery()
{
std::string name{m_filename};
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char const Character) { return static_cast<char>(std::tolower(Character)); });
auto const file{name + ".scn"};
std::ofstream output(Global.asCurrentSceneryPath + file, std::ios::binary);
if (false == output.is_open())
{
m_status = STR("The file can't be written");
return false;
}
auto const now{std::time(nullptr)};
char date[32];
std::strftime(date, sizeof(date), "%Y-%m-%d", std::localtime(&now));
char reference[96];
std::snprintf(reference, sizeof(reference), "//$g PUWG1992 %.3f %.3f", m_map.point().x / 1000.0, m_map.point().y / 1000.0);
if (m_realistic)
{
auto const &stored{EditorSettings.orthophoto()};
editor_orthophoto::config map;
map.radius = stored.radius;
map.height = stored.height;
map.opacity = stored.opacity;
map.year = stored.year;
map.hires = stored.hires;
map.drape = stored.drape;
map.lift = stored.lift;
map.in_scene = stored.in_scene;
output << reference << "\r\n";
output << "//$o " << editor_orthophoto::mark(map, true, false) << "\r\n";
}
else
std::snprintf(reference, sizeof(reference), "fictional");
if (m_title[0] != '\0')
output << "// " << m_title << "\r\n";
output << "// created in the editor " << date << "\r\n\r\n";
output << "atmo 0.423 0.702 1.0 25000 25000 0.70 0.80 0.9 0 endatmo\r\n";
output << "time 12:00 5:00 20:00 endtime\r\n\r\n";
output << "FirstInit\r\n";
output.close();
WriteLog("Scenery wizard: created " + file + " at " + reference);
Global.SceneryFile = file;
Global.local_start_vehicle = "ghostview";
Global.editor_session = true;
Application.pop_mode();
Application.push_mode(eu07_application::mode::scenarioloader);
return true;
}