16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 00:49:19 +02:00
This commit is contained in:
milek7
2019-08-09 00:45:38 +02:00
parent 540b21113e
commit 1626864bfe
14 changed files with 493 additions and 475 deletions

View File

@@ -3,7 +3,7 @@
#include "simulation.h"
ui::keymapper_panel::keymapper_panel()
: ui_panel(STR("Keymapper"), true)
: ui_panel(STR("Keymapper"), false)
{
keyboard.init();
}

View File

@@ -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();
}

View File

@@ -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;
};

View File

@@ -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();
}

View File

@@ -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

View File

@@ -6,12 +6,9 @@
#include <filesystem>
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<scenery_desc*>(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);
}
}
}

View File

@@ -1,38 +1,7 @@
#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();
}
};
#include "scenery_scanner.h"
namespace ui
{
@@ -44,10 +13,7 @@ class scenerylist_panel : public ui_panel
void render() override;
private:
std::vector<scenery_desc> scenarios;
scenery_scanner scanner;
scenery_desc const *selected_scenery = nullptr;
void scan_scenarios();
void scan_scn(std::string path);
};
} // namespace ui

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include <filesystem>
#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<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();
}
};
class scenery_scanner {
public:
std::vector<scenery_desc> scenarios;
void scan();
private:
void scan_scn(std::string path);
};

View File

@@ -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 &param)
{
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 &param, 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 &param)
{
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 &param)
{
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;
}
}

View File

@@ -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<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::string, deferred_image> group_icons;
std::map<std::filesystem::path, std::shared_ptr<vehicle_desc>> vehicles;
std::map<std::string, std::set<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 &param);
void parse_coupling_rule(const std::string &target, const std::string &param);
void parse_texture_rule(const std::string &target, const std::string &param);
void parse_texture_info(const std::string &target, const std::string &param, 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;
};
}

View File

@@ -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<void*>(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<void*>(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0));
if (ImGui::BeginDragDropSource()) {
ImGui::Image(reinterpret_cast<void*>(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 &param)
{
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 &param, 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 &param)
{
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 &param)
{
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;
}
}

View File

@@ -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<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::string, deferred_image> group_icons;
std::map<std::filesystem::path, std::shared_ptr<vehicle_desc>> vehicles;
std::map<std::string, std::set<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 &param);
void parse_coupling_rule(const std::string &target, const std::string &param);
void parse_texture_rule(const std::string &target, const std::string &param);
void parse_texture_info(const std::string &target, const std::string &param, 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
{
@@ -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<const vehicle_desc> selected_vehicle;
@@ -105,7 +22,5 @@ private:
bool display_by_groups = false;
vehicles_bank bank;
const deferred_image *lastdef = nullptr;
};
} // namespace ui