mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-19 03:09:18 +02:00
add missing files
This commit is contained in:
89
launcher/keymapper.cpp
Normal file
89
launcher/keymapper.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "stdafx.h"
|
||||
#include "keymapper.h"
|
||||
#include "simulation.h"
|
||||
|
||||
ui::keymapper_panel::keymapper_panel()
|
||||
: ui_panel(STR("Keymapper"), true)
|
||||
{
|
||||
keyboard.init();
|
||||
}
|
||||
|
||||
bool ui::keymapper_panel::key(int key)
|
||||
{
|
||||
if (!is_open || bind_active == user_command::none)
|
||||
return false;
|
||||
|
||||
auto it = keyboard.keytonamemap.find(key);
|
||||
if (it == keyboard.keytonamemap.end())
|
||||
return false;
|
||||
|
||||
if (Global.shiftState)
|
||||
key |= keyboard_input::keymodifier::shift;
|
||||
if (Global.ctrlState)
|
||||
key |= keyboard_input::keymodifier::control;
|
||||
|
||||
keyboard.bindings().insert_or_assign(bind_active, key);
|
||||
bind_active = user_command::none;
|
||||
keyboard.bind();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ui::keymapper_panel::render()
|
||||
{
|
||||
if (!is_open)
|
||||
return;
|
||||
|
||||
auto const panelname{(title.empty() ? m_name : title) + "###" + m_name};
|
||||
|
||||
if (ImGui::Begin(panelname.c_str(), &is_open)) {
|
||||
if (ImGui::Button(STR_C("Load")))
|
||||
keyboard.init();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(STR_C("Save")))
|
||||
keyboard.dump_bindings();
|
||||
|
||||
for (const std::pair<user_command, int> &binding : keyboard.bindings()) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text(simulation::Commands_descriptions[static_cast<std::size_t>(binding.first)].name.c_str());
|
||||
|
||||
std::string label;
|
||||
|
||||
if (binding.second & keyboard_input::keymodifier::control)
|
||||
label += "ctrl + ";
|
||||
if (binding.second & keyboard_input::keymodifier::shift)
|
||||
label += "shift + ";
|
||||
|
||||
auto it = keyboard.keytonamemap.find(binding.second & 0xFFFF);
|
||||
if (it != keyboard.keytonamemap.end())
|
||||
label += it->second;
|
||||
|
||||
label = ToUpper(label);
|
||||
|
||||
bool styles_pushed = false;
|
||||
if (bind_active == binding.first) {
|
||||
label = "?";
|
||||
ImVec4 active_col = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, active_col);
|
||||
styles_pushed = true;
|
||||
}
|
||||
|
||||
label += "##" + std::to_string((int)binding.first);
|
||||
|
||||
ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - 150);
|
||||
if (ImGui::Button(label.c_str(), ImVec2(150, 0))) {
|
||||
if (bind_active == binding.first)
|
||||
bind_active = user_command::none;
|
||||
else
|
||||
bind_active = binding.first;
|
||||
}
|
||||
|
||||
if (styles_pushed)
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
21
launcher/keymapper.h
Normal file
21
launcher/keymapper.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
#include "driverkeyboardinput.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class keymapper_panel : public ui_panel
|
||||
{
|
||||
public:
|
||||
keymapper_panel();
|
||||
|
||||
void render() override;
|
||||
bool key(int key);
|
||||
|
||||
private:
|
||||
driverkeyboard_input keyboard;
|
||||
|
||||
user_command bind_active = user_command::none;
|
||||
};
|
||||
} // namespace ui
|
||||
43
launcher/launchermode.cpp
Normal file
43
launcher/launchermode.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "stdafx.h"
|
||||
#include "launcher/launchermode.h"
|
||||
#include "launcher/launcheruilayer.h"
|
||||
#include "application.h"
|
||||
#include "simulation.h"
|
||||
#include "Globals.h"
|
||||
|
||||
launcher_mode::launcher_mode()
|
||||
{
|
||||
m_userinterface = std::make_shared<launcher_ui>();
|
||||
}
|
||||
|
||||
bool launcher_mode::init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool launcher_mode::update()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void launcher_mode::enter()
|
||||
{
|
||||
Application.set_cursor( GLFW_CURSOR_NORMAL );
|
||||
|
||||
simulation::is_ready = false;
|
||||
|
||||
m_userinterface->set_background( "logo" );
|
||||
Application.set_title(Global.AppName);
|
||||
}
|
||||
|
||||
void launcher_mode::exit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void launcher_mode::on_key(const int Key, const int Scancode, const int Action, const int Mods)
|
||||
{
|
||||
Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false;
|
||||
Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false;
|
||||
m_userinterface->on_key(Key, Action);
|
||||
}
|
||||
45
launcher/launchermode.h
Normal file
45
launcher/launchermode.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "applicationmode.h"
|
||||
|
||||
class launcher_mode : public application_mode {
|
||||
|
||||
public:
|
||||
// constructors
|
||||
launcher_mode();
|
||||
// methods
|
||||
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
||||
bool
|
||||
init() override;
|
||||
// mode-specific update of simulation data. returns: false on error, true otherwise
|
||||
bool
|
||||
update() override;
|
||||
// maintenance method, called when the mode is activated
|
||||
void
|
||||
enter() override;
|
||||
// maintenance method, called when the mode is deactivated
|
||||
void
|
||||
exit() override;
|
||||
// input handlers
|
||||
void
|
||||
on_key( int const Key, int const Scancode, int const Action, int const Mods );
|
||||
void
|
||||
on_cursor_pos( double const Horizontal, double const Vertical ) override { ; }
|
||||
void
|
||||
on_mouse_button( int const Button, int const Action, int const Mods ) override { ; }
|
||||
void
|
||||
on_scroll( double const Xoffset, double const Yoffset ) override { ; }
|
||||
void
|
||||
on_event_poll() override { ; }
|
||||
bool
|
||||
is_command_processor() override { return false; }
|
||||
};
|
||||
18
launcher/launcheruilayer.cpp
Normal file
18
launcher/launcheruilayer.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "stdafx.h"
|
||||
#include "launcher/launcheruilayer.h"
|
||||
|
||||
launcher_ui::launcher_ui()
|
||||
{
|
||||
add_external_panel(&m_scenerylist_panel);
|
||||
add_external_panel(&m_keymapper_panel);
|
||||
add_external_panel(&m_mainmenu_panel);
|
||||
add_external_panel(&m_vehiclepicker_panel);
|
||||
}
|
||||
|
||||
bool launcher_ui::on_key(const int Key, const int Action)
|
||||
{
|
||||
if (m_keymapper_panel.key(Key))
|
||||
return true;
|
||||
|
||||
return ui_layer::on_key(Key, Action);
|
||||
}
|
||||
28
launcher/launcheruilayer.h
Normal file
28
launcher/launcheruilayer.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
#include "launcher/scenery_list.h"
|
||||
#include "launcher/keymapper.h"
|
||||
#include "launcher/mainmenu.h"
|
||||
#include "launcher/vehicle_picker.h"
|
||||
|
||||
class launcher_ui : public ui_layer {
|
||||
public:
|
||||
launcher_ui();
|
||||
bool on_key(const int Key, const int Action) override;
|
||||
|
||||
private:
|
||||
ui::scenerylist_panel m_scenerylist_panel;
|
||||
ui::keymapper_panel m_keymapper_panel;
|
||||
ui::mainmenu_panel m_mainmenu_panel;
|
||||
ui::vehiclepicker_panel m_vehiclepicker_panel;
|
||||
};
|
||||
26
launcher/mainmenu.cpp
Normal file
26
launcher/mainmenu.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "stdafx.h"
|
||||
#include "launcher/mainmenu.h"
|
||||
|
||||
ui::mainmenu_panel::mainmenu_panel()
|
||||
: ui_panel(STR("Main menu"), true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ui::mainmenu_panel::render()
|
||||
{
|
||||
if (!is_open)
|
||||
return;
|
||||
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse;
|
||||
ImVec2 display_size = ImGui::GetIO().DisplaySize;
|
||||
ImGui::SetNextWindowPos(ImVec2(display_size.x * 0.66f, display_size.y / 2.0f));
|
||||
ImGui::SetNextWindowSize(ImVec2(200, -1));
|
||||
|
||||
if (ImGui::Begin(m_name.c_str(), nullptr, flags)) {
|
||||
ImGui::Button(STR_C("Scenario list"), ImVec2(-1, 0));
|
||||
ImGui::Button(STR_C("Settings"), ImVec2(-1, 0));
|
||||
ImGui::Button(STR_C("Quit"), ImVec2(-1, 0));
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
14
launcher/mainmenu.h
Normal file
14
launcher/mainmenu.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class mainmenu_panel : public ui_panel
|
||||
{
|
||||
public:
|
||||
mainmenu_panel();
|
||||
|
||||
void render() override;
|
||||
};
|
||||
} // namespace ui
|
||||
165
launcher/scenery_list.cpp
Normal file
165
launcher/scenery_list.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#include "stdafx.h"
|
||||
#include "scenery_list.h"
|
||||
#include "imgui/imgui.h"
|
||||
#include "utilities.h"
|
||||
#include "renderer.h"
|
||||
#include <filesystem>
|
||||
|
||||
ui::scenerylist_panel::scenerylist_panel()
|
||||
: ui_panel(STR("Scenario list"), true)
|
||||
{
|
||||
scan_scenarios();
|
||||
|
||||
std::sort(scenarios.begin(), scenarios.end(),
|
||||
[](const scenery_desc &a, const scenery_desc &b) { return a.path < b.path; });
|
||||
}
|
||||
|
||||
void ui::scenerylist_panel::render()
|
||||
{
|
||||
if (!is_open)
|
||||
return;
|
||||
|
||||
auto const panelname{(title.empty() ? m_name : title) + "###" + m_name};
|
||||
|
||||
if (ImGui::Begin(panelname.c_str(), &is_open)) {
|
||||
ImGui::Columns(3);
|
||||
|
||||
if (ImGui::BeginChild("child1")) {
|
||||
std::string prev_prefix;
|
||||
bool collapse_open = false;
|
||||
|
||||
for (auto const &desc : scenarios) {
|
||||
std::string name = desc.path.stem();
|
||||
std::string prefix = name.substr(0, name.find_first_of("-_"));
|
||||
if (prefix.empty())
|
||||
prefix = name;
|
||||
|
||||
bool just_opened = false;
|
||||
if (prefix != prev_prefix) {
|
||||
collapse_open = ImGui::CollapsingHeader(prefix.c_str());
|
||||
just_opened = ImGui::IsItemDeactivated();
|
||||
prev_prefix = prefix;
|
||||
}
|
||||
|
||||
if (collapse_open) {
|
||||
if (just_opened)
|
||||
selected_scenery = &desc;
|
||||
|
||||
ImGui::Indent(10.0f);
|
||||
if (ImGui::Selectable(name.c_str(), &desc == selected_scenery))
|
||||
selected_scenery = &desc;
|
||||
ImGui::Unindent(10.0f);
|
||||
}
|
||||
}
|
||||
} ImGui::EndChild();
|
||||
|
||||
ImGui::NextColumn();
|
||||
|
||||
if (ImGui::BeginChild("child2")) {
|
||||
if (selected_scenery) {
|
||||
ImGui::TextWrapped("%s", selected_scenery->name.c_str());
|
||||
ImGui::TextWrapped("%s", selected_scenery->description.c_str());
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
for (auto const &link : selected_scenery->links) {
|
||||
if (ImGui::Button(link.second.c_str(), ImVec2(-1, 0))) {
|
||||
std::string file = ToLower(link.first);
|
||||
#ifdef _WIN32
|
||||
system(("start \"" + file + "\"").c_str());
|
||||
#elif __linux__
|
||||
system(("xdg-open \"" + file + "\"").c_str());
|
||||
#elif __APPLE__
|
||||
system(("open \"" + file + "\"").c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
} ImGui::EndChild();
|
||||
|
||||
ImGui::NextColumn();
|
||||
|
||||
if (selected_scenery) {
|
||||
if (ImGui::BeginChild("child3", ImVec2(0, 0), false, ImGuiWindowFlags_NoScrollbar)) {
|
||||
if (!selected_scenery->image_path.empty()) {
|
||||
scenery_desc *desc = const_cast<scenery_desc*>(selected_scenery);
|
||||
desc->image = GfxRenderer.Fetch_Texture(selected_scenery->image_path, true);
|
||||
desc->image_path.clear();
|
||||
}
|
||||
|
||||
if (selected_scenery->image != null_handle) {
|
||||
opengl_texture &tex = GfxRenderer.Texture(selected_scenery->image);
|
||||
tex.create();
|
||||
|
||||
if (tex.is_ready) {
|
||||
float avail_width = ImGui::GetContentRegionAvailWidth();
|
||||
float height = avail_width / tex.width() * tex.height();
|
||||
|
||||
ImGui::Image(reinterpret_cast<void *>(tex.id), ImVec2(avail_width, height), ImVec2(0, 1), ImVec2(1, 0));
|
||||
}
|
||||
}
|
||||
} ImGui::EndChild();
|
||||
|
||||
if (ImGui::Begin(STR_C("Select trainset"))) {
|
||||
for (auto const &trainset : selected_scenery->trainsets) {
|
||||
ImGui::Selectable("Trainset", false);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ui::scenerylist_panel::scan_scenarios()
|
||||
{
|
||||
for (auto &f : std::filesystem::directory_iterator("scenery")) {
|
||||
std::filesystem::path path(f.path());
|
||||
|
||||
if (*(path.filename().string().begin()) == '$')
|
||||
continue;
|
||||
|
||||
if (string_ends_with(path, ".scn"))
|
||||
scan_scn(path);
|
||||
}
|
||||
}
|
||||
|
||||
void ui::scenerylist_panel::scan_scn(std::string path)
|
||||
{
|
||||
scenarios.emplace_back();
|
||||
scenery_desc &desc = scenarios.back();
|
||||
desc.path = path;
|
||||
|
||||
std::ifstream stream(path, std::ios_base::binary | std::ios_base::in);
|
||||
|
||||
std::string line;
|
||||
while (std::getline(stream, line))
|
||||
{
|
||||
if (line.size() < 6 || !string_starts_with(line, "//$"))
|
||||
continue;
|
||||
|
||||
if (line[3] == 'i')
|
||||
desc.image_path = "scenery/images/" + line.substr(5);
|
||||
else if (line[3] == 'n')
|
||||
desc.name = line.substr(5);
|
||||
else if (line[3] == 'd')
|
||||
desc.description += line.substr(5) + '\n';
|
||||
else if (line[3] == 'f') {
|
||||
std::string lang;
|
||||
std::string file;
|
||||
std::string label;
|
||||
|
||||
std::istringstream stream(line.substr(5));
|
||||
stream >> lang >> file;
|
||||
std::getline(stream, label);
|
||||
|
||||
desc.links.push_back(std::make_pair(file, label));
|
||||
}
|
||||
else if (line[3] == 'o') {
|
||||
desc.trainsets.emplace_back();
|
||||
trainset_desc &trainset = desc.trainsets.back();
|
||||
trainset.name = line.substr(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
launcher/scenery_list.h
Normal file
53
launcher/scenery_list.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
#include <filesystem>
|
||||
|
||||
struct trainset_desc {
|
||||
std::string description;
|
||||
|
||||
std::string name;
|
||||
std::string track;
|
||||
|
||||
float offset { 0.f };
|
||||
float velocity { 0.f };
|
||||
|
||||
std::vector<std::string> vehicles;
|
||||
std::vector<int> couplings;
|
||||
};
|
||||
|
||||
struct scenery_desc {
|
||||
std::filesystem::path path;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string image_path;
|
||||
texture_handle image = 0;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> links;
|
||||
std::vector<trainset_desc> trainsets;
|
||||
|
||||
std::string title() {
|
||||
if (!name.empty())
|
||||
return name;
|
||||
else
|
||||
return path.stem().string();
|
||||
}
|
||||
};
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class scenerylist_panel : public ui_panel
|
||||
{
|
||||
public:
|
||||
scenerylist_panel();
|
||||
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
std::vector<scenery_desc> scenarios;
|
||||
scenery_desc const *selected_scenery = nullptr;
|
||||
|
||||
void scan_scenarios();
|
||||
void scan_scn(std::string path);
|
||||
};
|
||||
} // namespace ui
|
||||
324
launcher/vehicle_picker.cpp
Normal file
324
launcher/vehicle_picker.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
#include "stdafx.h"
|
||||
#include "launcher/vehicle_picker.h"
|
||||
#include "renderer.h"
|
||||
|
||||
GLuint ui::deferred_image::get()
|
||||
{
|
||||
if (!path.empty()) {
|
||||
image = GfxRenderer.Fetch_Texture(path, true);
|
||||
path.clear();
|
||||
}
|
||||
|
||||
if (image != null_handle) {
|
||||
opengl_texture &tex = GfxRenderer.Texture(image);
|
||||
tex.create();
|
||||
|
||||
if (tex.is_ready)
|
||||
return tex.id;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
glm::ivec2 ui::deferred_image::size()
|
||||
{
|
||||
if (image != null_handle) {
|
||||
opengl_texture &tex = GfxRenderer.Texture(image);
|
||||
return glm::ivec2(tex.width(), tex.height());
|
||||
}
|
||||
return glm::ivec2();
|
||||
}
|
||||
|
||||
ui::vehiclepicker_panel::vehiclepicker_panel()
|
||||
: ui_panel(STR("Select vehicle"), true)
|
||||
{
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
bank.scan_textures();
|
||||
auto diff = std::chrono::high_resolution_clock::now() - now;
|
||||
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(diff).count() << std::endl;
|
||||
filter.resize(256, 0);
|
||||
}
|
||||
|
||||
void ui::vehiclepicker_panel::render()
|
||||
{
|
||||
if (!is_open)
|
||||
return;
|
||||
|
||||
static std::map<vehicle_type, std::string> type_names =
|
||||
{
|
||||
{ vehicle_type::electric_loco, STRN("Electric locos") },
|
||||
{ vehicle_type::diesel_loco, STRN("Diesel locos") },
|
||||
{ vehicle_type::steam_loco, STRN("Steam locos") },
|
||||
{ vehicle_type::railcar, STRN("Railcars") },
|
||||
{ vehicle_type::emu, STRN("EMU") },
|
||||
{ vehicle_type::utility, STRN("Utility") },
|
||||
{ vehicle_type::draisine, STRN("Draisines") },
|
||||
{ vehicle_type::tram, STRN("Trams") },
|
||||
{ vehicle_type::carriage, STRN("Carriages") },
|
||||
{ vehicle_type::truck, STRN("Trucks") },
|
||||
{ vehicle_type::bus, STRN("Buses") },
|
||||
{ vehicle_type::car, STRN("Cars") },
|
||||
{ vehicle_type::man, STRN("People") },
|
||||
{ vehicle_type::animal, STRN("Animals") },
|
||||
{ vehicle_type::unknown, STRN("Unknown") }
|
||||
};
|
||||
|
||||
if (ImGui::Begin(m_name.c_str())) {
|
||||
ImGui::InputText("##filter", &filter[0], filter.size());
|
||||
|
||||
ImGui::Columns(3);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f));
|
||||
|
||||
if (ImGui::BeginChild("box1")) {
|
||||
for (auto const &e : type_names) {
|
||||
deferred_image *image;
|
||||
auto it = bank.category_icons.find(e.first);
|
||||
if (it != bank.category_icons.end())
|
||||
image = &it->second;
|
||||
|
||||
if (selectable_image(Translations.lookup_s(e.second).c_str(), e.first == selected_type, image))
|
||||
selected_type = e.first;
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::NextColumn();
|
||||
|
||||
if (ImGui::BeginChild("box2")) {
|
||||
for (auto const &v : bank.vehicles) {
|
||||
auto desc = v.second;
|
||||
if (selected_type == desc->type) {
|
||||
if (desc->matching_skinsets.size() == 0)
|
||||
continue;
|
||||
|
||||
auto image = &desc->matching_skinsets[0].mini;
|
||||
|
||||
if (selectable_image(desc->path.stem().c_str(), desc == selected_vehicle, image))
|
||||
selected_vehicle = desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::NextColumn();
|
||||
|
||||
if (ImGui::BeginChild("box3")) {
|
||||
for (auto const &v : bank.vehicles) {
|
||||
auto desc = v.second;
|
||||
if (selected_vehicle == desc) {
|
||||
for (auto &skin : desc->matching_skinsets) {
|
||||
auto image = &skin.mini;
|
||||
|
||||
if (selectable_image(skin.skins[0].stem().c_str(), &skin == selected_skinset, image))
|
||||
selected_skinset = &skin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, deferred_image* image)
|
||||
{
|
||||
bool ret = ImGui::Selectable(desc, selected, 0, ImVec2(0, 30));
|
||||
|
||||
if (!image)
|
||||
return ret;
|
||||
|
||||
GLuint tex = image->get();
|
||||
if (tex != -1) {
|
||||
glm::ivec2 size = image->size();
|
||||
float width = 30.0f / size.y * size.x;
|
||||
ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - width);
|
||||
ImGui::Image(reinterpret_cast<void*>(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ui::vehicles_bank::scan_textures()
|
||||
{
|
||||
for (auto &f : std::filesystem::recursive_directory_iterator("dynamic")) {
|
||||
if (f.path().filename() != "textures.txt")
|
||||
continue;
|
||||
|
||||
std::fstream stream(f.path(), std::ios_base::binary | std::ios_base::in);
|
||||
ctx_path = f.path().parent_path();
|
||||
|
||||
std::string line;
|
||||
while (std::getline(stream, line))
|
||||
{
|
||||
if (line.size() < 3)
|
||||
continue;
|
||||
if (line.back() == '\r')
|
||||
line.pop_back();
|
||||
|
||||
parse_entry(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ui::vehicles_bank::parse_entry(const std::string &line)
|
||||
{
|
||||
std::string content;
|
||||
std::string comments;
|
||||
|
||||
size_t pos = line.find("//");
|
||||
if (pos != -1)
|
||||
comments = line.substr(pos);
|
||||
content = line.substr(0, pos);
|
||||
|
||||
std::istringstream stream(content);
|
||||
|
||||
std::string target;
|
||||
std::getline(stream, target, '=');
|
||||
|
||||
std::string param;
|
||||
while (std::getline(stream, param, '=')) {
|
||||
if (line[0] == '!')
|
||||
parse_category_entry(param);
|
||||
else if (line[0] == '*' && line[1] == '*')
|
||||
parse_texture_rule(target.substr(2), param);
|
||||
else if (line[0] == '*')
|
||||
parse_coupling_rule(target.substr(1), param);
|
||||
else if (line[0] != '@')
|
||||
parse_texture_info(target, param, comments);
|
||||
}
|
||||
}
|
||||
|
||||
void ui::vehicles_bank::parse_category_entry(const std::string ¶m)
|
||||
{
|
||||
static std::unordered_map<char, vehicle_type> type_map = {
|
||||
{ 'e', vehicle_type::electric_loco },
|
||||
{ 's', vehicle_type::diesel_loco },
|
||||
{ 'p', vehicle_type::steam_loco },
|
||||
{ 'a', vehicle_type::railcar },
|
||||
{ 'z', vehicle_type::emu },
|
||||
{ 'r', vehicle_type::utility },
|
||||
{ 'd', vehicle_type::draisine },
|
||||
{ 't', vehicle_type::tram },
|
||||
{ 'c', vehicle_type::truck },
|
||||
{ 'b', vehicle_type::bus },
|
||||
{ 'o', vehicle_type::car },
|
||||
{ 'h', vehicle_type::man },
|
||||
{ 'f', vehicle_type::animal },
|
||||
};
|
||||
|
||||
ctx_type = vehicle_type::unknown;
|
||||
|
||||
std::istringstream stream(param);
|
||||
|
||||
std::string tok;
|
||||
std::getline(stream, tok, ',');
|
||||
|
||||
if (tok.size() < 1)
|
||||
return;
|
||||
|
||||
auto it = type_map.find(tok[0]);
|
||||
if (it != type_map.end())
|
||||
ctx_type = it->second;
|
||||
else if (tok[0] >= 'A' && tok[0] <= 'Z')
|
||||
ctx_type = vehicle_type::carriage;
|
||||
|
||||
std::string mini;
|
||||
std::getline(stream, mini, ',');
|
||||
|
||||
category_icons.emplace(ctx_type, "textures/mini/" + ToLower(mini));
|
||||
}
|
||||
|
||||
void ui::vehicles_bank::parse_texture_info(const std::string &target, const std::string ¶m, const std::string &comment)
|
||||
{
|
||||
std::istringstream stream(param);
|
||||
|
||||
std::string model, mini, miniplus;
|
||||
|
||||
std::getline(stream, model, ',');
|
||||
std::getline(stream, mini, ',');
|
||||
std::getline(stream, miniplus, ',');
|
||||
|
||||
skin_set set;
|
||||
set.group = mini;
|
||||
if (!miniplus.empty())
|
||||
set.mini = deferred_image("textures/mini/" + ToLower(miniplus));
|
||||
|
||||
std::istringstream tex_stream(target);
|
||||
std::string texture;
|
||||
while (std::getline(tex_stream, texture, '|')) {
|
||||
auto path = ctx_path;
|
||||
path.append(texture);
|
||||
set.skins.push_back(path);
|
||||
}
|
||||
|
||||
get_vehicle(model)->matching_skinsets.push_back(set);
|
||||
}
|
||||
|
||||
void ui::vehicles_bank::parse_coupling_rule(const std::string &target, const std::string ¶m)
|
||||
{
|
||||
if (param == "?")
|
||||
return;
|
||||
|
||||
std::istringstream stream(param);
|
||||
|
||||
int coupling_flag;
|
||||
stream >> coupling_flag;
|
||||
stream.ignore(1000, ',');
|
||||
|
||||
std::string connected;
|
||||
std::getline(stream, connected, ',');
|
||||
|
||||
std::string param1, param2;
|
||||
std::getline(stream, param1, ',');
|
||||
std::getline(stream, param2, ',');
|
||||
|
||||
coupling_rule rule;
|
||||
rule.coupled_vehicle = get_vehicle(target);
|
||||
rule.coupling_flag = coupling_flag;
|
||||
|
||||
get_vehicle(connected)->coupling_rules.push_back(rule);
|
||||
}
|
||||
|
||||
void ui::vehicles_bank::parse_texture_rule(const std::string &target, const std::string ¶m)
|
||||
{
|
||||
std::istringstream stream(param);
|
||||
|
||||
std::string prev;
|
||||
std::getline(stream, prev, ',');
|
||||
|
||||
std::string replace_rule;
|
||||
while (std::getline(stream, replace_rule, ',')) {
|
||||
if (replace_rule == "-")
|
||||
break;
|
||||
|
||||
std::istringstream rule_stream(replace_rule);
|
||||
|
||||
std::string src, dst;
|
||||
std::getline(rule_stream, src, '-');
|
||||
std::getline(rule_stream, dst, '-');
|
||||
|
||||
texture_rule rule;
|
||||
rule.previous_vehicle = get_vehicle(prev);
|
||||
rule.replace_rules.emplace_back(src, dst);
|
||||
|
||||
get_vehicle(target)->texture_rules.push_back(rule);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ui::vehicle_desc> ui::vehicles_bank::get_vehicle(const std::string &name)
|
||||
{
|
||||
auto path = ctx_path;
|
||||
path.append(name);
|
||||
auto it = vehicles.find(path);
|
||||
if (it != vehicles.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else {
|
||||
auto desc = std::make_shared<vehicle_desc>();
|
||||
desc->type = ctx_type;
|
||||
desc->path = path;
|
||||
vehicles.emplace(path, desc);
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
102
launcher/vehicle_picker.h
Normal file
102
launcher/vehicle_picker.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include "uilayer.h"
|
||||
|
||||
namespace ui {
|
||||
enum class vehicle_type {
|
||||
none = -1,
|
||||
electric_loco,
|
||||
diesel_loco,
|
||||
steam_loco,
|
||||
railcar,
|
||||
emu,
|
||||
utility,
|
||||
draisine,
|
||||
tram,
|
||||
carriage,
|
||||
truck,
|
||||
bus,
|
||||
car,
|
||||
man,
|
||||
animal,
|
||||
unknown
|
||||
};
|
||||
|
||||
class deferred_image {
|
||||
public:
|
||||
deferred_image() = default;
|
||||
deferred_image(const std::string &p) : path(p) { }
|
||||
|
||||
GLuint get();
|
||||
glm::ivec2 size();
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
texture_handle image = 0;
|
||||
};
|
||||
|
||||
struct skin_set {
|
||||
std::vector<std::filesystem::path> skins;
|
||||
deferred_image mini;
|
||||
std::string group;
|
||||
};
|
||||
|
||||
struct vehicle_desc;
|
||||
struct texture_rule {
|
||||
std::shared_ptr<vehicle_desc> previous_vehicle;
|
||||
std::vector<std::pair<std::string, std::string>> replace_rules;
|
||||
};
|
||||
|
||||
struct coupling_rule {
|
||||
std::shared_ptr<vehicle_desc> coupled_vehicle;
|
||||
int coupling_flag;
|
||||
};
|
||||
|
||||
struct vehicle_desc {
|
||||
vehicle_type type;
|
||||
std::filesystem::path path;
|
||||
|
||||
std::vector<skin_set> matching_skinsets;
|
||||
std::vector<coupling_rule> coupling_rules;
|
||||
std::vector<texture_rule> texture_rules;
|
||||
};
|
||||
|
||||
class vehicles_bank {
|
||||
public:
|
||||
std::unordered_map<vehicle_type, deferred_image> category_icons;
|
||||
std::map<std::filesystem::path, std::shared_ptr<vehicle_desc>> vehicles;
|
||||
std::map<std::string, std::vector<std::shared_ptr<vehicle_desc>>> group_map;
|
||||
void scan_textures();
|
||||
|
||||
private:
|
||||
void parse_entry(const std::string &line);
|
||||
void parse_category_entry(const std::string ¶m);
|
||||
void parse_coupling_rule(const std::string &target, const std::string ¶m);
|
||||
void parse_texture_rule(const std::string &target, const std::string ¶m);
|
||||
void parse_texture_info(const std::string &target, const std::string ¶m, const std::string &comment);
|
||||
|
||||
std::shared_ptr<vehicle_desc> get_vehicle(const std::string &name);
|
||||
|
||||
vehicle_type ctx_type = vehicle_type::unknown;
|
||||
std::filesystem::path ctx_path;
|
||||
std::string ctx_model;
|
||||
};
|
||||
|
||||
class vehiclepicker_panel : public ui_panel
|
||||
{
|
||||
public:
|
||||
vehiclepicker_panel();
|
||||
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
bool selectable_image(const char *desc, bool selected, deferred_image *image);
|
||||
|
||||
vehicle_type selected_type = vehicle_type::none;
|
||||
std::shared_ptr<vehicle_desc> selected_vehicle;
|
||||
const skin_set *selected_skinset = nullptr;
|
||||
|
||||
vehicles_bank bank;
|
||||
std::string filter;
|
||||
};
|
||||
} // namespace ui
|
||||
Reference in New Issue
Block a user