Add American V8 preset, carb fuel transport, and adaptive desktop audio
This commit is contained in:
@@ -57,14 +57,15 @@ void draw_label(sf::RenderWindow& window, const sf::Font* font, const std::strin
|
||||
}
|
||||
|
||||
std::optional<ScenarioKind> choose_scenario(sf::RenderWindow& window, const sf::Font* font) {
|
||||
const std::array<sf::FloatRect, 4> cards{{{{32, 110}, {656, 84}}, {{32, 206}, {656, 84}}, {{32, 302}, {656, 84}}, {{32, 398}, {656, 84}}}};
|
||||
const sf::FloatRect start_button{{32, 506}, {656, 52}};
|
||||
const std::array<const char*, 4> titles{"600 cc parallel twin", "YZ125 two-stroke", "Saab B205 / 9-5 wagon", "600 cc twin + VZ21-size turbo"};
|
||||
const std::array<const char*, 4> descriptions{
|
||||
const std::array<sf::FloatRect, 5> cards{{{{32, 110}, {656, 72}}, {{32, 190}, {656, 72}}, {{32, 270}, {656, 72}}, {{32, 350}, {656, 72}}, {{32, 430}, {656, 72}}}};
|
||||
const sf::FloatRect start_button{{32, 522}, {656, 52}};
|
||||
const std::array<const char*, 5> titles{"600 cc parallel twin", "YZ125 two-stroke", "Saab B205 / 9-5 wagon", "600 cc twin + VZ21-size turbo", "1980s American 5.0 V8"};
|
||||
const std::array<const char*, 5> descriptions{
|
||||
"Four-stroke twin, motorcycle test and dyno",
|
||||
"125 cc single, expansion chamber, motorcycle test and dyno",
|
||||
"2.0 litre inline-four, GT17 turbo, ECU boost control and five-speed wagon",
|
||||
"Coupled turbine/compressor, shaft inertia and pressure diagnostics"};
|
||||
"Coupled turbine/compressor, shaft inertia and pressure diagnostics",
|
||||
"EFI cross-plane V8, heavy flywheel, independent exhaust banks"};
|
||||
int selected = 0;
|
||||
while (window.isOpen()) {
|
||||
while (const auto event = window.pollEvent()) {
|
||||
@@ -72,26 +73,27 @@ std::optional<ScenarioKind> choose_scenario(sf::RenderWindow& window, const sf::
|
||||
if (const auto* key = event->getIf<sf::Event::KeyPressed>()) {
|
||||
switch (key->code) {
|
||||
case sf::Keyboard::Key::Escape: return std::nullopt;
|
||||
case sf::Keyboard::Key::Up: selected = (selected + 3) % 4; break;
|
||||
case sf::Keyboard::Key::Up: selected = (selected + 4) % 5; break;
|
||||
case sf::Keyboard::Key::Down:
|
||||
case sf::Keyboard::Key::Tab: selected = (selected + 1) % 4; break;
|
||||
case sf::Keyboard::Key::Tab: selected = (selected + 1) % 5; break;
|
||||
case sf::Keyboard::Key::Num1: selected = 0; break;
|
||||
case sf::Keyboard::Key::Num2: selected = 1; break;
|
||||
case sf::Keyboard::Key::Num3: selected = 2; break;
|
||||
case sf::Keyboard::Key::Num4: selected = 3; break;
|
||||
case sf::Keyboard::Key::Num5: selected = 4; break;
|
||||
case sf::Keyboard::Key::Enter: return static_cast<ScenarioKind>(selected);
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (const auto* move = event->getIf<sf::Event::MouseMoved>()) {
|
||||
const auto point = window.mapPixelToCoords(move->position);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 5; ++i)
|
||||
if (cards[i].contains(point)) selected = i;
|
||||
}
|
||||
if (const auto* click = event->getIf<sf::Event::MouseButtonReleased>();
|
||||
click && click->button == sf::Mouse::Button::Left) {
|
||||
const auto point = window.mapPixelToCoords(click->position);
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 5; ++i)
|
||||
if (cards[i].contains(point)) return static_cast<ScenarioKind>(i);
|
||||
if (start_button.contains(point)) return static_cast<ScenarioKind>(selected);
|
||||
}
|
||||
@@ -99,7 +101,7 @@ std::optional<ScenarioKind> choose_scenario(sf::RenderWindow& window, const sf::
|
||||
window.clear({9, 12, 17});
|
||||
draw_label(window, font, "FluidSim", {32, 24}, sf::Color::White, 28);
|
||||
draw_label(window, font, "Choose a scenario to start", {32, 66}, {180, 190, 205}, 16);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
sf::RectangleShape card(cards[i].size);
|
||||
card.setPosition(cards[i].position);
|
||||
card.setFillColor(i == selected ? sf::Color(24, 46, 60) : sf::Color(18, 24, 32));
|
||||
@@ -115,7 +117,7 @@ std::optional<ScenarioKind> choose_scenario(sf::RenderWindow& window, const sf::
|
||||
start.setPosition(start_button.position);
|
||||
start.setFillColor({35, 105, 115});
|
||||
window.draw(start);
|
||||
draw_label(window, font, "Start selected scenario [Enter]", {52, 519}, sf::Color::White, 17);
|
||||
draw_label(window, font, "Start selected scenario [Enter]", {52, 537}, sf::Color::White, 17);
|
||||
draw_label(window, font, "Click a scenario or use Up/Down. Esc: quit", {32, 574}, {150, 165, 180}, 12);
|
||||
window.display();
|
||||
}
|
||||
@@ -296,13 +298,13 @@ void draw_dyno_curve(sf::RenderWindow& window, const sf::Font* font, const DynoC
|
||||
|
||||
void draw_dashboard(sf::RenderWindow& window, const sf::Font* font, const ScenarioSnapshot& state,
|
||||
float throttle_target, float brake, double playback_speed, std::size_t buffer_fill,
|
||||
std::size_t buffer_capacity, bool time_warp, std::uint64_t underrun_blocks) {
|
||||
std::size_t buffer_capacity, bool time_warp, std::uint64_t underrun_blocks, bool auto_gain) {
|
||||
std::ostringstream status;
|
||||
status << (time_warp ? "[Space] normal speed" : "[Space] real time")
|
||||
<< " Sim " << std::fixed << std::setprecision(3) << playback_speed << "x"
|
||||
<< " Audio buffer " << buffer_fill << "/" << buffer_capacity
|
||||
<< " Underruns " << underrun_blocks
|
||||
<< (state.cylinder_count == 4 ? "\nWagon " : "\nBike ") << std::setprecision(1) << state.speed_kmh << " km/h Gear "
|
||||
<< (state.cylinder_count == 8 ? "\nCoupe " : state.cylinder_count == 4 ? "\nWagon " : "\nBike ") << std::setprecision(1) << state.speed_kmh << " km/h Gear "
|
||||
<< (state.gear == 0 ? "N" : std::to_string(state.gear))
|
||||
<< " Throttle " << state.throttle * 100.0f << "% / target " << throttle_target * 100.0f << "% [W, up/down]"
|
||||
<< " Clutch " << state.clutch * 100.0f << "% [C] Engine load " << brake * 100.0f << "% [left/right]"
|
||||
@@ -310,6 +312,7 @@ void draw_dashboard(sf::RenderWindow& window, const sf::Font* font, const Scenar
|
||||
<< "\nScene [R]: " << scene_name(state.audio_scene) << " " << (state.fuel_cut ? "FUEL CUT" : (state.idle_control ? "IDLE CONTROL" : "RUNNING"));
|
||||
if (!state.two_stroke)
|
||||
status << " Mechanical [M]: " << (state.mechanical_sound_enabled ? "ON" : "OFF");
|
||||
status << " Auto gain [G]: " << (auto_gain ? "ON" : "OFF");
|
||||
if (font) {
|
||||
sf::RectangleShape panel({1260.0f, 92.0f});
|
||||
panel.setPosition({10.0f, 10.0f});
|
||||
@@ -350,7 +353,7 @@ void draw_two_stroke_scene(sf::RenderWindow& window,const sf::Font* font,const S
|
||||
draw_label(window,font,"CRANKCASE",{455,385},sf::Color::White,14);
|
||||
draw_pipe(window,s,0,460,30,170);
|
||||
draw_volume(window,s.intake_pressure,{{180,425},{95,70}});
|
||||
draw_label(window,font,"INTAKE",{180,400},sf::Color::White,14);
|
||||
draw_label(window,font,"CARB / INTAKE",{180,400},sf::Color::White,14);
|
||||
draw_pipe(window,s,1,460,285,445);
|
||||
draw_label(window,font,s.reed_open?"REED OPEN":"REED CLOSED",{290,485},s.reed_open?sf::Color::Green:sf::Color::Red,12);
|
||||
draw_pipe(window,s,2,350,315,450);
|
||||
@@ -365,7 +368,8 @@ void draw_two_stroke_scene(sf::RenderWindow& window,const sf::Font* font,const S
|
||||
draw_label(window,font,s.racing_exhaust ? "HEADER / DIFFUSERS / BELLY / BAFFLE / STINGER" : "STRAIGHT EXHAUST",{670,205},sf::Color::White,13);
|
||||
std::ostringstream pressures;
|
||||
pressures<<std::fixed<<std::setprecision(1)<<"Cylinder "<<s.cylinder_pressure1/1000<<" kPa Crankcase "
|
||||
<<s.crankcase_pressure/1000<<" kPa Intake "<<s.intake_pressure/1000<<" kPa";
|
||||
<<s.crankcase_pressure/1000<<" kPa Intake "<<s.intake_pressure/1000<<" kPa Carb AFR "
|
||||
<<s.target_afr<<":1";
|
||||
draw_label(window,font,pressures.str(),{22,580},sf::Color::White,17);
|
||||
draw_label(window,font,"54 x 54.5 mm | 8.2:1 trapped compression | estimated pipe/ports/CDI | fixed-open power valve",
|
||||
{22,625},{180,190,200},11);
|
||||
@@ -459,14 +463,38 @@ void draw_b205_scene(sf::RenderWindow& window, const sf::Font* font, const Scena
|
||||
|
||||
void draw_scene(sf::RenderWindow& window, const sf::Font* font, const ScenarioSnapshot& state,
|
||||
float throttle_target, float brake, double playback_speed, std::size_t buffer_fill,
|
||||
std::size_t buffer_capacity, bool time_warp, DynoCurve& dyno_curve, std::uint64_t underrun_blocks) {
|
||||
std::size_t buffer_capacity, bool time_warp, DynoCurve& dyno_curve, std::uint64_t underrun_blocks, bool auto_gain) {
|
||||
const float power_kw = state.average_power / 1000.0f;
|
||||
dyno_curve.update(state.rpm, power_kw, state.average_torque);
|
||||
if (state.two_stroke) draw_two_stroke_scene(window, font, state);
|
||||
if (state.cylinder_count == 8) {
|
||||
window.clear({9,12,17});
|
||||
draw_label(window, font, "American 5.0 V8 | EFI / ECU | 7000 RPM | heavy flywheel", {25,185}, sf::Color::White, 16);
|
||||
draw_pipe(window, state, 0, 205, 25, 115);
|
||||
draw_volume(window, state.intake_pressure, {{120,200},{60,25}});
|
||||
draw_label(window, font, "ONE THROTTLE / SHARED PLENUM", {850,225}, sf::Color::White, 12);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
const float x = 70 + (i%4)*185;
|
||||
const float top = i < 4 ? 230.f : 455.f;
|
||||
const std::string name = "CYL " + std::to_string(i+1);
|
||||
draw_cylinder(window, font, state.cylinder_pressures[i], state.piston_fractions[i], top,
|
||||
name.c_str(), state.intake_areas[i]>1e-7f, state.exhaust_areas[i]>1e-7f, x);
|
||||
draw_pipe(window, state, 9+i, top+150, x-10, x+90);
|
||||
draw_pipe(window, state, 1+i, top+125, x-10, x+90);
|
||||
draw_graph_line(window, {x+90,top+150}, {830,top+150}, {200,120,80});
|
||||
}
|
||||
draw_graph_line(window, {830,380}, {850,300}, {200,120,80});
|
||||
draw_graph_line(window, {830,605}, {850,375}, {200,120,80});
|
||||
draw_pipe(window, state, 17, 300, 850, 1250);
|
||||
draw_pipe(window, state, 18, 375, 850, 1250);
|
||||
draw_label(window, font, "SEPARATE BANK COLLECTORS / DUAL TAILS", {850,410}, sf::Color::White, 11);
|
||||
draw_label(window, font, "EFI AFR " + std::to_string(state.target_afr), {850,430}, sf::Color::White, 13);
|
||||
draw_label(window, font, "302-class | shared 4 L intake, 12 cm runners | 7:1 compression | 750 rpm idle", {25,690}, {180,190,205}, 12);
|
||||
}
|
||||
else if (state.two_stroke) draw_two_stroke_scene(window, font, state);
|
||||
else if (state.cylinder_count == 4) draw_b205_scene(window, font, state);
|
||||
else draw_twin_scene(window, font, state);
|
||||
draw_dashboard(window, font, state, throttle_target, brake, playback_speed, buffer_fill,
|
||||
buffer_capacity, time_warp, underrun_blocks);
|
||||
buffer_capacity, time_warp, underrun_blocks, auto_gain);
|
||||
draw_dyno_curve(window, font, dyno_curve, 860, 455, 400, 250, state.rpm, power_kw);
|
||||
window.display();
|
||||
}
|
||||
@@ -486,8 +514,8 @@ int main(int argc, char** argv) {
|
||||
if((option=="--scenario"||option=="--scene"||option=="--exhaust"||option=="--turbo")&&i+1<argc){
|
||||
const std::string value=argv[++i];
|
||||
if(option=="--scenario"){
|
||||
if(value!="twin"&&value!="two-stroke"&&value!="b205"){std::cerr<<"Choose twin, two-stroke or b205\n";return 2;}
|
||||
selected_kind=value=="b205" ? ScenarioKind::SaabB205 :
|
||||
if(value!="twin"&&value!="two-stroke"&&value!="b205"&&value!="v8"){std::cerr<<"Choose twin, two-stroke, b205 or v8\n";return 2;}
|
||||
selected_kind=value=="v8" ? ScenarioKind::AmericanV8 : value=="b205" ? ScenarioKind::SaabB205 :
|
||||
(value=="two-stroke" ? ScenarioKind::TwoStroke : ScenarioKind::Twin);
|
||||
scenario_from_args=true;
|
||||
}else if(option=="--turbo"){
|
||||
@@ -505,7 +533,7 @@ int main(int argc, char** argv) {
|
||||
else if(value=="woodland")selected_scene=OutdoorScene::Woodland;
|
||||
else {std::cerr<<"Choose dry, field, wall or woodland\n";return 2;}
|
||||
}
|
||||
}else{std::cerr<<"Usage: fluidsim_desktop [--scenario twin|two-stroke|b205] [--scene dry|field|wall|woodland] [--exhaust racing|straight] [--turbo none|vz21|gt17]\n";return 2;}
|
||||
}else{std::cerr<<"Usage: fluidsim_desktop [--scenario twin|two-stroke|b205|v8] [--scene dry|field|wall|woodland] [--exhaust racing|straight] [--turbo none|vz21|gt17]\n";return 2;}
|
||||
}
|
||||
const sf::Vector2u initial_size = scenario_from_args ? sf::Vector2u{window_width, window_height}
|
||||
: sf::Vector2u{720, 606};
|
||||
@@ -542,7 +570,7 @@ int main(int argc, char** argv) {
|
||||
std::cerr<<"Use gt17 with b205 or vz21 with twin\n";return 2;
|
||||
}
|
||||
}
|
||||
window.setTitle(selected_kind == ScenarioKind::TurboTwin ? "FluidSim - twin + VZ21 turbo" : selected_kind == ScenarioKind::SaabB205 ? "FluidSim - Saab B205 / 9-5 wagon" :
|
||||
window.setTitle(selected_kind == ScenarioKind::AmericanV8 ? "FluidSim - 1980s American 5.0 V8" : selected_kind == ScenarioKind::TurboTwin ? "FluidSim - twin + VZ21 turbo" : selected_kind == ScenarioKind::SaabB205 ? "FluidSim - Saab B205 / 9-5 wagon" :
|
||||
(selected_kind == ScenarioKind::TwoStroke ? "FluidSim - YZ125 two-stroke" : "FluidSim - parallel twin"));
|
||||
DesktopScenario scenario(selected_kind, two_stroke_config, turbo_name!="none");
|
||||
scenario.set_audio_scene(selected_scene);
|
||||
@@ -600,6 +628,7 @@ int main(int argc, char** argv) {
|
||||
scenario.set_audio_scene(selected_scene);
|
||||
break;
|
||||
case sf::Keyboard::Key::M: scenario.toggle_mechanical_sound(); break;
|
||||
case sf::Keyboard::Key::G: audio.set_auto_gain(!audio.auto_gain()); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -629,7 +658,7 @@ int main(int argc, char** argv) {
|
||||
scenario.set_controls(throttle_current, brake_current, clutch_current);
|
||||
|
||||
draw_scene(window, font_ptr, scenario.snapshot(), throttle_target, brake_current,
|
||||
current_speed, ring.available_samples(), ring_capacity, time_warp, dyno_curve, audio.underrun_blocks());
|
||||
current_speed, ring.available_samples(), ring_capacity, time_warp, dyno_curve, audio.underrun_blocks(), audio.auto_gain());
|
||||
}
|
||||
|
||||
simulation.request_stop();
|
||||
|
||||
Reference in New Issue
Block a user