// Copyright (C) 2001--2019 Sam Varner
//
// This file is part of Vamos Automotive Simulator.
//
// Vamos is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vamos is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vamos. If not, see <http://www.gnu.org/licenses/>.
#include "../body/Gl_Car.hpp"
#include "../media/Ac3d.hpp"
#include "../track/Strip_Track.hpp"
#include "../world/Gl_World.hpp"
#include "../world/Interactive_Driver.hpp"
#include "../world/Robot_Driver.hpp"
#include "../world/Sounds.hpp"
#include "Options.hpp"
#include <boost/filesystem.hpp>
using namespace Vamos_Geometry;
using namespace Vamos_Media;
using namespace Vamos_Track;
using namespace Vamos_World;
namespace fs = boost::filesystem;
struct Entry
{
std::string file;
bool interactive;
double time;
};
using V_Entry = std::vector<Entry>;
std::string get_path(std::string file, std::string section, bool extend)
{
std::string path("../data/" + section + "/" + file + (extend ? ".xml" : ""));
if (fs::exists(path))
return path;
path = DATADIR "/" + section + "/" + file + (extend ? ".xml" : "");
if (fs::exists(path))
return path;
return file;
}
void read_input(Options& opt, V_Entry& entries)
{
std::ifstream in(opt.input_file.c_str());
in >> opt.track_file;
int lap;
double time;
in >> lap >> lap >> time;
while (true)
{
std::string file, name, type;
in >> file >> name >> type >> lap >> time;
if (!in)
break;
entries.push_back({file, type == "interactive", time});
}
std::sort(entries.begin(), entries.end(),
[](const Entry& e1, const Entry& e2){ return e1.time < e2.time; });
opt.number_of_cars = entries.size();
}
void get_entries(Options& opt, V_Entry& entries)
{
if (!opt.input_file.empty())
return read_input(opt, entries);
opt.track_file = get_path(opt.track_file, "tracks", true);
std::vector<std::string> car_files;
fs::path car_path(get_path(opt.car_file, "cars", false));
if (fs::is_directory(car_path))
{
for (auto it = fs::directory_iterator(car_path);
it != fs::directory_iterator() && car_files.size() < opt.number_of_cars; ++it)
if (it->path().extension() == ".xml")
car_files.push_back(it->path().native());
std::sort(car_files.begin(), car_files.end());
}
else
car_files.push_back(get_path(opt.car_file, "cars", true));
std::sort(car_files.begin(), car_files.end());
std::vector<std::string>::const_iterator it = car_files.begin();
while (entries.size() < opt.number_of_cars)
{
entries.push_back({*it, false, 0});
if (++it == car_files.end())
it = car_files.begin();
}
if (!opt.demo)
entries.back().interactive = true;
}
int main(int argc, char* argv[])
{
Options opt(argc, argv);
if (!opt)
std::exit(opt.exit_status());
Strip_Track track;
Atmosphere air{1.2, Three_Vector(0.0, 0.0, 0.0)};
Sounds sounds(opt.volume);
Gl_World world(track, air, sounds, opt.full_screen);
try
{
V_Entry entries;
get_entries(opt, entries);
track.read(opt.data_dir, opt.track_file);
if (!opt.map_mode)
{
bool robots = false;
bool interactive = false;
Three_Matrix orientation;
int place = 0;
for (const auto& entry : entries)
{
Vamos_Body::Gl_Car* car = new Vamos_Body::Gl_Car(
track.grid_position(++place, opt.number_of_cars, opt.qualifying), orientation);
car->read(opt.data_dir, entry.file);
car->start_engine();
if (entry.interactive)
{
interactive = true;
Interactive_Driver* driver = new Interactive_Driver(*car);
world.add_car(*car, *driver);
world.set_focused_car(place - 1);
}
else
{
robots = true;
car->adjust_robot_parameters(opt.performance, opt.performance, opt.performance);
Robot_Driver* driver = new Robot_Driver(*car, track, world.get_gravity());
if (opt.qualifying)
driver->qualify();
driver->interact(opt.interact);
driver->show_steering_target(opt.show_line);
world.add_car(*car, *driver);
}
}
if (robots && !interactive)
world.set_focused_car(0);
world.cars_can_interact(opt.interact);
}
world.read(get_path(opt.world_file, "worlds", true),
get_path(opt.controls_file, "controls", true));
if (!opt.map_mode)
sounds.read(opt.data_dir + "sounds/", "default-sounds.xml");
}
catch (XML_Exception& error)
{
std::cerr << error.what() << std::endl;
std::exit(EXIT_FAILURE);
}
catch (Vamos_Media::Ac3d_Exception& error)
{
std::cerr << error.what() << std::endl;
std::exit(EXIT_FAILURE);
}
if (opt.show_line || opt.demo || opt.number_of_cars > 1)
{
track.build_racing_line();
track.show_racing_line(opt.show_line);
}
world.start(opt.qualifying, opt.laps);
std::ostringstream name;
name << (opt.qualifying ? "qualifying" : "race") << "-results";
world.write_results(name.str());
return EXIT_SUCCESS;
}