From 1626864bfe6af65ca0e102c3211e313149fb9e6c Mon Sep 17 00:00:00 2001 From: milek7 Date: Fri, 9 Aug 2019 00:45:38 +0200 Subject: [PATCH] cleanup --- CMakeLists.txt | 3 +- launcher/keymapper.cpp | 2 +- launcher/launcheruilayer.cpp | 22 ++- launcher/launcheruilayer.h | 4 +- launcher/mainmenu.cpp | 26 ---- launcher/mainmenu.h | 14 -- launcher/scenery_list.cpp | 91 +++--------- launcher/scenery_list.h | 38 +---- launcher/scenery_scanner.cpp | 57 ++++++++ launcher/scenery_scanner.h | 46 ++++++ launcher/textures_scanner.cpp | 227 +++++++++++++++++++++++++++++ launcher/textures_scanner.h | 90 ++++++++++++ launcher/vehicle_picker.cpp | 259 +++------------------------------- launcher/vehicle_picker.h | 89 +----------- 14 files changed, 493 insertions(+), 475 deletions(-) delete mode 100644 launcher/mainmenu.cpp delete mode 100644 launcher/mainmenu.h create mode 100644 launcher/scenery_scanner.cpp create mode 100644 launcher/scenery_scanner.h create mode 100644 launcher/textures_scanner.cpp create mode 100644 launcher/textures_scanner.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bb71dbc9..78b5fce5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,7 +170,8 @@ set(SOURCES "launcher/launcheruilayer.cpp" "launcher/vehicle_picker.cpp" "launcher/keymapper.cpp" -"launcher/mainmenu.cpp" +"launcher/textures_scanner.cpp" +"launcher/scenery_scanner.cpp" ) if (USE_IMGUI_GL3) diff --git a/launcher/keymapper.cpp b/launcher/keymapper.cpp index 0b23d5ad..b952e739 100644 --- a/launcher/keymapper.cpp +++ b/launcher/keymapper.cpp @@ -3,7 +3,7 @@ #include "simulation.h" ui::keymapper_panel::keymapper_panel() - : ui_panel(STR("Keymapper"), true) + : ui_panel(STR("Keymapper"), false) { keyboard.init(); } diff --git a/launcher/launcheruilayer.cpp b/launcher/launcheruilayer.cpp index 900cf58f..6ca93e9b 100644 --- a/launcher/launcheruilayer.cpp +++ b/launcher/launcheruilayer.cpp @@ -1,11 +1,11 @@ #include "stdafx.h" #include "launcher/launcheruilayer.h" +#include "application.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); } @@ -16,3 +16,23 @@ bool launcher_ui::on_key(const int Key, const int Action) return ui_layer::on_key(Key, Action); } + +void launcher_ui::render_() +{ + 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(STR_C("Main menu"), nullptr, flags)) { + if (ImGui::Button(STR_C("Scenario list"), ImVec2(-1, 0))) + m_scenerylist_panel.is_open = !m_scenerylist_panel.is_open; + if (ImGui::Button(STR_C("Vehicle list"), ImVec2(-1, 0))) + m_vehiclepicker_panel.is_open = !m_vehiclepicker_panel.is_open; + if (ImGui::Button(STR_C("Keymapper"), ImVec2(-1, 0))) + m_keymapper_panel.is_open = !m_keymapper_panel.is_open; + if (ImGui::Button(STR_C("Quit"), ImVec2(-1, 0))) + Application.queue_quit(); + } + ImGui::End(); +} diff --git a/launcher/launcheruilayer.h b/launcher/launcheruilayer.h index 9d20b51c..a38b4492 100644 --- a/launcher/launcheruilayer.h +++ b/launcher/launcheruilayer.h @@ -12,7 +12,6 @@ http://mozilla.org/MPL/2.0/. #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 { @@ -21,8 +20,9 @@ public: bool on_key(const int Key, const int Action) override; private: + void render_() override; + ui::scenerylist_panel m_scenerylist_panel; ui::keymapper_panel m_keymapper_panel; - ui::mainmenu_panel m_mainmenu_panel; ui::vehiclepicker_panel m_vehiclepicker_panel; }; diff --git a/launcher/mainmenu.cpp b/launcher/mainmenu.cpp deleted file mode 100644 index 83994693..00000000 --- a/launcher/mainmenu.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#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(); -} diff --git a/launcher/mainmenu.h b/launcher/mainmenu.h deleted file mode 100644 index db5bfec8..00000000 --- a/launcher/mainmenu.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "uilayer.h" - -namespace ui -{ -class mainmenu_panel : public ui_panel -{ - public: - mainmenu_panel(); - - void render() override; -}; -} // namespace ui diff --git a/launcher/scenery_list.cpp b/launcher/scenery_list.cpp index 424f124b..dde7e9f4 100644 --- a/launcher/scenery_list.cpp +++ b/launcher/scenery_list.cpp @@ -6,12 +6,9 @@ #include ui::scenerylist_panel::scenerylist_panel() - : ui_panel(STR("Scenario list"), true) + : ui_panel(STR("Scenario list"), false) { - scan_scenarios(); - - std::sort(scenarios.begin(), scenarios.end(), - [](const scenery_desc &a, const scenery_desc &b) { return a.path < b.path; }); + scanner.scan(); } void ui::scenerylist_panel::render() @@ -24,11 +21,11 @@ void ui::scenerylist_panel::render() if (ImGui::Begin(panelname.c_str(), &is_open)) { ImGui::Columns(3); - if (ImGui::BeginChild("child1")) { + if (ImGui::BeginChild("child1", ImVec2(0, -50))) { std::string prev_prefix; bool collapse_open = false; - for (auto const &desc : scenarios) { + for (auto const &desc : scanner.scenarios) { std::string name = desc.path.stem().string(); std::string prefix = name.substr(0, name.find_first_of("-_")); if (prefix.empty()) @@ -55,7 +52,7 @@ void ui::scenerylist_panel::render() ImGui::NextColumn(); - if (ImGui::BeginChild("child2")) { + if (ImGui::BeginChild("child2", ImVec2(0, -50))) { if (selected_scenery) { ImGui::TextWrapped("%s", selected_scenery->name.c_str()); ImGui::TextWrapped("%s", selected_scenery->description.c_str()); @@ -80,7 +77,7 @@ void ui::scenerylist_panel::render() ImGui::NextColumn(); if (selected_scenery) { - if (ImGui::BeginChild("child3", ImVec2(0, 0), false, ImGuiWindowFlags_NoScrollbar)) { + if (ImGui::BeginChild("child3", ImVec2(0, -50), false, ImGuiWindowFlags_NoScrollbar)) { if (!selected_scenery->image_path.empty()) { scenery_desc *desc = const_cast(selected_scenery); desc->image = GfxRenderer.Fetch_Texture(selected_scenery->image_path, true); @@ -99,67 +96,25 @@ void ui::scenerylist_panel::render() } } } ImGui::EndChild(); - - if (ImGui::Begin(STR_C("Select trainset"))) { - for (auto const &trainset : selected_scenery->trainsets) { - ImGui::Selectable("Trainset", false); - } - } - ImGui::End(); } + ImGui::Columns(); + ImGui::Separator(); + + if (ImGui::BeginChild("child4")) { + if (selected_scenery) { + ImGui::Columns(2); + + if (ImGui::BeginChild("child5", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) { + for (auto const &trainset : selected_scenery->trainsets) { + ImGui::Selectable("trainset", false); + } + } ImGui::EndChild(); + + ImGui::NextColumn(); + //ImGui::Button(STR_C("Launch")); + } + } ImGui::EndChild(); } 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.string(), ".scn")) - scan_scn(path.string()); - } -} - -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); - } - } -} diff --git a/launcher/scenery_list.h b/launcher/scenery_list.h index 2514790d..70df4cd8 100644 --- a/launcher/scenery_list.h +++ b/launcher/scenery_list.h @@ -1,38 +1,7 @@ #pragma once #include "uilayer.h" -#include - -struct trainset_desc { - std::string description; - - std::string name; - std::string track; - - float offset { 0.f }; - float velocity { 0.f }; - - std::vector vehicles; - std::vector couplings; -}; - -struct scenery_desc { - std::filesystem::path path; - std::string name; - std::string description; - std::string image_path; - texture_handle image = 0; - - std::vector> links; - std::vector trainsets; - - std::string title() { - if (!name.empty()) - return name; - else - return path.stem().string(); - } -}; +#include "scenery_scanner.h" namespace ui { @@ -44,10 +13,7 @@ class scenerylist_panel : public ui_panel void render() override; private: - std::vector scenarios; + scenery_scanner scanner; scenery_desc const *selected_scenery = nullptr; - - void scan_scenarios(); - void scan_scn(std::string path); }; } // namespace ui diff --git a/launcher/scenery_scanner.cpp b/launcher/scenery_scanner.cpp new file mode 100644 index 00000000..47ae7b11 --- /dev/null +++ b/launcher/scenery_scanner.cpp @@ -0,0 +1,57 @@ +#include "stdafx.h" +#include "scenery_scanner.h" + +void scenery_scanner::scan() +{ + 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.string(), ".scn")) + scan_scn(path.string()); + } + + std::sort(scenarios.begin(), scenarios.end(), + [](const scenery_desc &a, const scenery_desc &b) { return a.path < b.path; }); +} + +void scenery_scanner::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); + } + } +} diff --git a/launcher/scenery_scanner.h b/launcher/scenery_scanner.h new file mode 100644 index 00000000..d95610dc --- /dev/null +++ b/launcher/scenery_scanner.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include "Texture.h" +#include "utilities.h" + +struct trainset_desc { + std::string description; + + std::string name; + std::string track; + + float offset { 0.f }; + float velocity { 0.f }; + + std::vector vehicles; + std::vector couplings; +}; + +struct scenery_desc { + std::filesystem::path path; + std::string name; + std::string description; + std::string image_path; + texture_handle image = 0; + + std::vector> links; + std::vector trainsets; + + std::string title() { + if (!name.empty()) + return name; + else + return path.stem().string(); + } +}; + +class scenery_scanner { +public: + std::vector scenarios; + + void scan(); + +private: + void scan_scn(std::string path); +}; diff --git a/launcher/textures_scanner.cpp b/launcher/textures_scanner.cpp new file mode 100644 index 00000000..0e6d53c5 --- /dev/null +++ b/launcher/textures_scanner.cpp @@ -0,0 +1,227 @@ +#include "stdafx.h" +#include "textures_scanner.h" +#include "renderer.h" +#include "utilities.h" + +GLuint ui::deferred_image::get() const +{ + 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; +} + +ui::deferred_image::operator bool() const +{ + return image != null_handle || !path.empty(); +} + +glm::ivec2 ui::deferred_image::size() const +{ + if (image != null_handle) { + opengl_texture &tex = GfxRenderer.Texture(image); + return glm::ivec2(tex.width(), tex.height()); + } + return glm::ivec2(); +} + + +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 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 (!mini.empty()) + group_icons.emplace(mini, std::move(deferred_image("textures/mini/" + ToLower(mini)))); + + if (!miniplus.empty()) + set.mini = std::move(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); + } + + auto vehicle = get_vehicle(model); + group_map[set.group].insert(vehicle); + vehicle->matching_skinsets.push_back(std::move(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::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(); + desc->type = ctx_type; + desc->path = path; + vehicles.emplace(path, desc); + return desc; + } +} diff --git a/launcher/textures_scanner.h b/launcher/textures_scanner.h new file mode 100644 index 00000000..4aaa17bc --- /dev/null +++ b/launcher/textures_scanner.h @@ -0,0 +1,90 @@ +#pragma once + +#include "Texture.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) { } + deferred_image(const deferred_image&) = delete; + deferred_image(deferred_image&&) = default; + deferred_image &operator=(deferred_image&&) = default; + operator bool() const; + + GLuint get() const; + glm::ivec2 size() const; + +private: + mutable std::string path; + mutable texture_handle image = 0; +}; + +struct skin_set { + std::vector skins; + deferred_image mini; + std::string group; +}; + +struct vehicle_desc; +struct texture_rule { + std::shared_ptr previous_vehicle; + std::vector> replace_rules; +}; + +struct coupling_rule { + std::shared_ptr coupled_vehicle; + int coupling_flag; +}; + +struct vehicle_desc { + vehicle_type type; + std::filesystem::path path; + + std::vector matching_skinsets; + std::vector coupling_rules; + std::vector texture_rules; +}; + +class vehicles_bank { +public: + std::unordered_map category_icons; + std::map group_icons; + + std::map> vehicles; + std::map>> 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 get_vehicle(const std::string &name); + + vehicle_type ctx_type = vehicle_type::unknown; + std::filesystem::path ctx_path; + std::string ctx_model; +}; +} diff --git a/launcher/vehicle_picker.cpp b/launcher/vehicle_picker.cpp index c80d73d7..9f575c44 100644 --- a/launcher/vehicle_picker.cpp +++ b/launcher/vehicle_picker.cpp @@ -2,40 +2,8 @@ #include "launcher/vehicle_picker.h" #include "renderer.h" -GLuint ui::deferred_image::get() const -{ - 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; -} - -ui::deferred_image::operator bool() const -{ - return image != null_handle || !path.empty(); -} - -glm::ivec2 ui::deferred_image::size() const -{ - 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) + : ui_panel(STR("Select vehicle"), false) { bank.scan_textures(); } @@ -64,7 +32,7 @@ void ui::vehiclepicker_panel::render() { vehicle_type::unknown, STRN("Unknown") } }; - if (ImGui::Begin(m_name.c_str())) { + if (ImGui::Begin(m_name.c_str(), &is_open)) { ImGui::Columns(3); ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f)); @@ -83,7 +51,7 @@ void ui::vehiclepicker_panel::render() ImGui::EndChild(); ImGui::NextColumn(); - ImGui::TextUnformatted("Group by: "); + ImGui::TextUnformatted(STR_C("Group by: ")); ImGui::SameLine(); if (ImGui::RadioButton(STR_C("type"), !display_by_groups)) display_by_groups = false; @@ -193,7 +161,7 @@ void ui::vehiclepicker_panel::render() auto skin = skinset_list[i]; std::string label = skin->skins[0].stem().string(); - if (selectable_image(label.c_str(), skin == selected_skinset, &skin->mini)) + if (selectable_image(label.c_str(), skin == selected_skinset, &skin->mini, true)) selected_skinset = skin; } } @@ -202,7 +170,7 @@ void ui::vehiclepicker_panel::render() ImGui::PopStyleVar(); } ImGui::End(); - +/* if (!lastdef) return; @@ -244,12 +212,14 @@ void ui::vehiclepicker_panel::render() } ImGui::End(); + */ } -bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, const deferred_image* image) +bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, const deferred_image* image, bool pickable) { bool ret = ImGui::Selectable(desc, selected, 0, ImVec2(0, 30)); - ImGui::SetItemAllowOverlap(); + if (pickable) + ImGui::SetItemAllowOverlap(); if (!image) return ret; @@ -260,211 +230,22 @@ bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, float width = 30.0f / size.y * size.x; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::Image(reinterpret_cast(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); - lastdef = image; - ImGui::PushID((void*)image); - ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); - ImGui::InvisibleButton(desc, ImVec2(width, 30)); + if (pickable) { + ImGui::PushID((void*)image); + ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); + ImGui::InvisibleButton(desc, ImVec2(width, 30)); - if (ImGui::BeginDragDropSource()) { - ImGui::Image(reinterpret_cast(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); + if (ImGui::BeginDragDropSource()) { + ImGui::Image(reinterpret_cast(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); - ImGui::SetDragDropPayload("skin", "aaaa", 5); - ImGui::EndDragDropSource(); + ImGui::SetDragDropPayload("skin", "aaaa", 5); + ImGui::EndDragDropSource(); + } + + ImGui::PopID(); } - - ImGui::PopID(); } 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 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 (!mini.empty()) - group_icons.emplace(mini, std::move(deferred_image("textures/mini/" + ToLower(mini)))); - - if (!miniplus.empty()) - set.mini = std::move(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); - } - - auto vehicle = get_vehicle(model); - group_map[set.group].insert(vehicle); - vehicle->matching_skinsets.push_back(std::move(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::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(); - desc->type = ctx_type; - desc->path = path; - vehicles.emplace(path, desc); - return desc; - } -} diff --git a/launcher/vehicle_picker.h b/launcher/vehicle_picker.h index bcac3d02..16c1b522 100644 --- a/launcher/vehicle_picker.h +++ b/launcher/vehicle_picker.h @@ -1,92 +1,9 @@ #pragma once #include "uilayer.h" +#include "textures_scanner.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) { } - deferred_image(const deferred_image&) = delete; - deferred_image(deferred_image&&) = default; - deferred_image &operator=(deferred_image&&) = default; - operator bool() const; - - GLuint get() const; - glm::ivec2 size() const; - -private: - mutable std::string path; - mutable texture_handle image = 0; -}; - -struct skin_set { - std::vector skins; - deferred_image mini; - std::string group; -}; - -struct vehicle_desc; -struct texture_rule { - std::shared_ptr previous_vehicle; - std::vector> replace_rules; -}; - -struct coupling_rule { - std::shared_ptr coupled_vehicle; - int coupling_flag; -}; - -struct vehicle_desc { - vehicle_type type; - std::filesystem::path path; - - std::vector matching_skinsets; - std::vector coupling_rules; - std::vector texture_rules; -}; - -class vehicles_bank { -public: - std::unordered_map category_icons; - std::map group_icons; - - std::map> vehicles; - std::map>> 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 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 { @@ -96,7 +13,7 @@ class vehiclepicker_panel : public ui_panel void render() override; private: - bool selectable_image(const char *desc, bool selected, const deferred_image *image); + bool selectable_image(const char *desc, bool selected, const deferred_image *image, bool pickable = false); vehicle_type selected_type = vehicle_type::none; std::shared_ptr selected_vehicle; @@ -105,7 +22,5 @@ private: bool display_by_groups = false; vehicles_bank bank; - - const deferred_image *lastdef = nullptr; }; } // namespace ui